Annotation of ntddk/src/network/tdi/stcnfg.c, revision 1.1

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1989-1993  Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     stcnfg.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This contains all routines necessary for the support of the dynamic
        !            12:     configuration of ST.
        !            13: 
        !            14: Revision History:
        !            15: 
        !            16: --*/
        !            17: 
        !            18: #include "st.h"
        !            19: 
        !            20: 
        !            21: //
        !            22: // Local functions used to access the registry.
        !            23: //
        !            24: 
        !            25: NTSTATUS
        !            26: StConfigureTransport (
        !            27:     IN PUNICODE_STRING RegistryPath,
        !            28:     IN PCONFIG_DATA * ConfigurationInfoPtr
        !            29:     );
        !            30: 
        !            31: VOID
        !            32: StFreeConfigurationInfo (
        !            33:     IN PCONFIG_DATA ConfigurationInfo
        !            34:     );
        !            35: 
        !            36: NTSTATUS
        !            37: StOpenParametersKey(
        !            38:     IN HANDLE StConfigHandle,
        !            39:     OUT PHANDLE ParametersHandle
        !            40:     );
        !            41: 
        !            42: VOID
        !            43: StCloseParametersKey(
        !            44:     IN HANDLE ParametersHandle
        !            45:     );
        !            46: 
        !            47: NTSTATUS
        !            48: StCountEntries(
        !            49:     IN PWSTR ValueName,
        !            50:     IN ULONG ValueType,
        !            51:     IN PVOID ValueData,
        !            52:     IN ULONG ValueLength,
        !            53:     IN PVOID Context,
        !            54:     IN PVOID EntryContext
        !            55:     );
        !            56: 
        !            57: NTSTATUS
        !            58: StAddBind(
        !            59:     IN PWSTR ValueName,
        !            60:     IN ULONG ValueType,
        !            61:     IN PVOID ValueData,
        !            62:     IN ULONG ValueLength,
        !            63:     IN PVOID Context,
        !            64:     IN PVOID EntryContext
        !            65:     );
        !            66: 
        !            67: NTSTATUS
        !            68: StAddExport(
        !            69:     IN PWSTR ValueName,
        !            70:     IN ULONG ValueType,
        !            71:     IN PVOID ValueData,
        !            72:     IN ULONG ValueLength,
        !            73:     IN PVOID Context,
        !            74:     IN PVOID EntryContext
        !            75:     );
        !            76: 
        !            77: VOID
        !            78: StReadLinkageInformation(
        !            79:     IN PWSTR RegistryPathBuffer,
        !            80:     IN PCONFIG_DATA * ConfigurationInfo
        !            81:     );
        !            82: 
        !            83: UINT
        !            84: StReadSizeInformation(
        !            85:     IN HANDLE ParametersHandle
        !            86:     );
        !            87: 
        !            88: ULONG
        !            89: StReadSingleParameter(
        !            90:     IN HANDLE ParametersHandle,
        !            91:     IN PWCHAR ValueName,
        !            92:     IN ULONG DefaultValue
        !            93:     );
        !            94: 
        !            95: VOID
        !            96: StWriteSingleParameter(
        !            97:     IN HANDLE ParametersHandle,
        !            98:     IN PWCHAR ValueName,
        !            99:     IN ULONG ValueData
        !           100:     );
        !           101: 
        !           102: VOID
        !           103: StSaveConfigInRegistry(
        !           104:     IN HANDLE ParametersHandle,
        !           105:     IN PCONFIG_DATA ConfigurationInfo
        !           106:     );
        !           107: 
        !           108: UINT
        !           109: StWstrLength(
        !           110:     IN PWSTR Wstr
        !           111:     );
        !           112: 
        !           113: #ifdef ALLOC_PRAGMA
        !           114: #pragma alloc_text(init,StWstrLength)
        !           115: #pragma alloc_text(init,StConfigureTransport)
        !           116: #pragma alloc_text(init,StFreeConfigurationInfo)
        !           117: #pragma alloc_text(init,StOpenParametersKey)
        !           118: #pragma alloc_text(init,StCloseParametersKey)
        !           119: #pragma alloc_text(init,StCountEntries)
        !           120: #pragma alloc_text(init,StAddBind)
        !           121: #pragma alloc_text(init,StAddExport)
        !           122: #pragma alloc_text(init,StReadLinkageInformation)
        !           123: #pragma alloc_text(init,StReadSingleParameter)
        !           124: #pragma alloc_text(init,StWriteSingleParameter)
        !           125: #pragma alloc_text(init,StSaveConfigInRegistry)
        !           126: #endif
        !           127: 
        !           128: 
        !           129: UINT
        !           130: StWstrLength(
        !           131:     IN PWSTR Wstr
        !           132:     )
        !           133: {
        !           134:     UINT Length = 0;
        !           135:     while (*Wstr++) {
        !           136:         Length += sizeof(WCHAR);
        !           137:     }
        !           138:     return Length;
        !           139: }
        !           140: 
        !           141: #define InsertAdapter(ConfigurationInfo, Subscript, Name)                \
        !           142: { \
        !           143:     PWSTR _S; \
        !           144:     PWSTR _N = (Name); \
        !           145:     UINT _L = StWstrLength(_N)+sizeof(WCHAR); \
        !           146:     _S = (PWSTR)ExAllocatePool(NonPagedPool, _L); \
        !           147:     if (_S != NULL) { \
        !           148:         RtlCopyMemory(_S, _N, _L); \
        !           149:         RtlInitUnicodeString (&(ConfigurationInfo)->Names[Subscript], _S); \
        !           150:     } \
        !           151: }
        !           152: 
        !           153: #define InsertDevice(ConfigurationInfo, Subscript, Name)                \
        !           154: { \
        !           155:     PWSTR _S; \
        !           156:     PWSTR _N = (Name); \
        !           157:     UINT _L = StWstrLength(_N)+sizeof(WCHAR); \
        !           158:     _S = (PWSTR)ExAllocatePool(NonPagedPool, _L); \
        !           159:     if (_S != NULL) { \
        !           160:         RtlCopyMemory(_S, _N, _L); \
        !           161:         RtlInitUnicodeString (&(ConfigurationInfo)->Names[(ConfigurationInfo)->DevicesOffset+Subscript], _S); \
        !           162:     } \
        !           163: }
        !           164: 
        !           165: 
        !           166: #define RemoveAdapter(ConfigurationInfo, Subscript)                \
        !           167:     ExFreePool ((ConfigurationInfo)->Names[Subscript].Buffer)
        !           168: 
        !           169: #define RemoveDevice(ConfigurationInfo, Subscript)                \
        !           170:     ExFreePool ((ConfigurationInfo)->Names[(ConfigurationInfo)->DevicesOffset+Subscript].Buffer)
        !           171: 
        !           172: 
        !           173: 
        !           174: //
        !           175: // These strings are used in various places by the registry.
        !           176: //
        !           177: 
        !           178: #define DECLARE_STRING(_str_) STATIC WCHAR Str ## _str_[] = L#_str_
        !           179: 
        !           180: DECLARE_STRING(Large);
        !           181: DECLARE_STRING(Medium);
        !           182: DECLARE_STRING(Small);
        !           183: 
        !           184: DECLARE_STRING(InitRequests);
        !           185: DECLARE_STRING(InitConnections);
        !           186: DECLARE_STRING(InitAddressFiles);
        !           187: DECLARE_STRING(InitAddresses);
        !           188: 
        !           189: DECLARE_STRING(MaxRequests);
        !           190: DECLARE_STRING(MaxConnections);
        !           191: DECLARE_STRING(MaxAddressFiles);
        !           192: DECLARE_STRING(MaxAddresses);
        !           193: 
        !           194: DECLARE_STRING(InitPackets);
        !           195: DECLARE_STRING(InitReceivePackets);
        !           196: DECLARE_STRING(InitReceiveBuffers);
        !           197: 
        !           198: DECLARE_STRING(SendPacketPoolSize);
        !           199: DECLARE_STRING(ReceivePacketPoolSize);
        !           200: DECLARE_STRING(MaxMemoryUsage);
        !           201: 
        !           202: 
        !           203: #define READ_HIDDEN_CONFIG(_Field) \
        !           204: { \
        !           205:     ConfigurationInfo->_Field = \
        !           206:         StReadSingleParameter( \
        !           207:              ParametersHandle, \
        !           208:              Str ## _Field, \
        !           209:              ConfigurationInfo->_Field); \
        !           210: }
        !           211: 
        !           212: #define WRITE_HIDDEN_CONFIG(_Field) \
        !           213: { \
        !           214:     StWriteSingleParameter( \
        !           215:         ParametersHandle, \
        !           216:         Str ## _Field, \
        !           217:         ConfigurationInfo->_Field); \
        !           218: }
        !           219: 
        !           220: 
        !           221: 
        !           222: NTSTATUS
        !           223: StConfigureTransport (
        !           224:     IN PUNICODE_STRING RegistryPath,
        !           225:     IN PCONFIG_DATA * ConfigurationInfoPtr
        !           226:     )
        !           227: /*++
        !           228: 
        !           229: Routine Description:
        !           230: 
        !           231:     This routine is called by ST to get information from the configuration
        !           232:     management routines. We read the registry, starting at RegistryPath,
        !           233:     to get the parameters. If they don't exist, we use the defaults
        !           234:     set in nbfcnfg.h file.
        !           235: 
        !           236: Arguments:
        !           237: 
        !           238:     RegistryPath - The name of ST's node in the registry.
        !           239: 
        !           240:     ConfigurationInfoPtr - A pointer to the configuration information structure.
        !           241: 
        !           242: Return Value:
        !           243: 
        !           244:     Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
        !           245:             otherwise.
        !           246: 
        !           247: --*/
        !           248: {
        !           249: 
        !           250:     NTSTATUS OpenStatus;
        !           251:     HANDLE ParametersHandle;
        !           252:     UINT StSize;
        !           253:     HANDLE StConfigHandle;
        !           254:     NTSTATUS Status;
        !           255:     ULONG Disposition;
        !           256:     PWSTR RegistryPathBuffer;
        !           257:     OBJECT_ATTRIBUTES TmpObjectAttributes;
        !           258:     PCONFIG_DATA ConfigurationInfo;
        !           259: 
        !           260: 
        !           261:     //
        !           262:     // Open the registry.
        !           263:     //
        !           264: 
        !           265:     InitializeObjectAttributes(
        !           266:         &TmpObjectAttributes,
        !           267:         RegistryPath,               // name
        !           268:         OBJ_CASE_INSENSITIVE,       // attributes
        !           269:         NULL,                       // root
        !           270:         NULL                        // security descriptor
        !           271:         );
        !           272: 
        !           273:     Status = ZwCreateKey(
        !           274:                  &StConfigHandle,
        !           275:                  KEY_WRITE,
        !           276:                  &TmpObjectAttributes,
        !           277:                  0,                 // title index
        !           278:                  NULL,              // class
        !           279:                  0,                 // create options
        !           280:                  &Disposition);     // disposition
        !           281: 
        !           282:     if (!NT_SUCCESS(Status)) {
        !           283:         StPrint1("ST: Could not open/create ST key: %lx\n", Status);
        !           284:         return Status;
        !           285:     }
        !           286: 
        !           287: 
        !           288:     OpenStatus = StOpenParametersKey (StConfigHandle, &ParametersHandle);
        !           289: 
        !           290:     if (OpenStatus != STATUS_SUCCESS) {
        !           291:         return OpenStatus;
        !           292:     }
        !           293: 
        !           294:     //
        !           295:     // Read in the NDIS binding information (if none is present
        !           296:     // the array will be filled with all known drivers).
        !           297:     //
        !           298:     // StReadLinkageInformation expects a null-terminated path,
        !           299:     // so we have to create one from the UNICODE_STRING.
        !           300:     //
        !           301: 
        !           302:     RegistryPathBuffer = (PWSTR)ExAllocatePool(
        !           303:                                     NonPagedPool,
        !           304:                                     RegistryPath->Length + sizeof(WCHAR));
        !           305:     if (RegistryPathBuffer == NULL) {
        !           306:         StCloseParametersKey (ParametersHandle);
        !           307:         return STATUS_INSUFFICIENT_RESOURCES;
        !           308:     }
        !           309:     RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
        !           310:     *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
        !           311: 
        !           312:     StReadLinkageInformation (RegistryPathBuffer, ConfigurationInfoPtr);
        !           313: 
        !           314:     if (*ConfigurationInfoPtr == NULL) {
        !           315:         ExFreePool (RegistryPathBuffer);
        !           316:         StCloseParametersKey (ParametersHandle);
        !           317:         return STATUS_INSUFFICIENT_RESOURCES;
        !           318:     }
        !           319:     ConfigurationInfo = *ConfigurationInfoPtr;
        !           320: 
        !           321: 
        !           322:     //
        !           323:     // Read the size parameter; this returns 0 if none is
        !           324:     // present, or 1 (Small), 2 (Medium) and 3 (Large).
        !           325:     //
        !           326: 
        !           327:     StSize = StReadSizeInformation (ParametersHandle);
        !           328: 
        !           329:     switch (StSize) {
        !           330: 
        !           331:         case 0:
        !           332:         case 1:
        !           333: 
        !           334:             //
        !           335:             // Default is Small.
        !           336:             //
        !           337: 
        !           338:             //
        !           339:             // These are the initial value used; the comment after
        !           340:             // each one shows the expected maximum (if every resource
        !           341:             // is at the expected maximum, ST should be very close
        !           342:             // to being out of memory).
        !           343:             //
        !           344:             // For now the "Max" values default to 0 (no limit).
        !           345:             //
        !           346: 
        !           347:             ConfigurationInfo->InitRequests = 5;         // 30
        !           348:             ConfigurationInfo->InitConnections = 1;      // 10
        !           349:             ConfigurationInfo->InitAddressFiles = 0;     // 10
        !           350:             ConfigurationInfo->InitAddresses = 0;        // 10
        !           351: 
        !           352:             //
        !           353:             // These are the initial values; remember that the
        !           354:             // resources above also allocate some of these each
        !           355:             // time they are allocated (shown in the comment).
        !           356:             //
        !           357: 
        !           358:             ConfigurationInfo->InitPackets = 30;         // + link + conn (40)
        !           359:             ConfigurationInfo->InitReceivePackets = 10;  // + link + addr (30)
        !           360:             ConfigurationInfo->InitReceiveBuffers = 5;   // + addr (15)
        !           361: 
        !           362:             //
        !           363:             // Set the size of the packet pools and the total
        !           364:             // allocateable by ST.
        !           365:             //
        !           366: 
        !           367:             ConfigurationInfo->SendPacketPoolSize = 100;
        !           368:             ConfigurationInfo->ReceivePacketPoolSize = 30;
        !           369:             ConfigurationInfo->MaxMemoryUsage = 100000;
        !           370: 
        !           371:             break;
        !           372: 
        !           373:         case 2:
        !           374: 
        !           375:             //
        !           376:             // Medium ST.
        !           377:             //
        !           378: 
        !           379:             //
        !           380:             // These are the initial value used; the comment after
        !           381:             // each one shows the expected maximum (if every resource
        !           382:             // is at the expected maximum, ST should be very close
        !           383:             // to being out of memory).
        !           384:             //
        !           385:             // For now the "Max" values default to 0 (no limit).
        !           386:             //
        !           387: 
        !           388:             ConfigurationInfo->InitRequests = 10;        // 100
        !           389:             ConfigurationInfo->InitConnections = 2;      // 64
        !           390:             ConfigurationInfo->InitAddressFiles = 1;     // 20
        !           391:             ConfigurationInfo->InitAddresses = 1;        // 20
        !           392: 
        !           393:             //
        !           394:             // These are the initial values; remember that the
        !           395:             // resources above also allocate some of these each
        !           396:             // time they are allocated (shown in the comment).
        !           397:             //
        !           398: 
        !           399:             ConfigurationInfo->InitPackets = 50;         // + link + conn (150)
        !           400:             ConfigurationInfo->InitReceivePackets = 15;  // + link + addr (100)
        !           401:             ConfigurationInfo->InitReceiveBuffers = 10;  // + addr (30)
        !           402: 
        !           403:             //
        !           404:             // Set the size of the packet pools and the total
        !           405:             // allocateable by ST.
        !           406:             //
        !           407: 
        !           408:             ConfigurationInfo->SendPacketPoolSize = 250;
        !           409:             ConfigurationInfo->ReceivePacketPoolSize = 100;
        !           410:             ConfigurationInfo->MaxMemoryUsage = 250000;
        !           411: 
        !           412:             break;
        !           413: 
        !           414:         case 3:
        !           415: 
        !           416:             //
        !           417:             // Big ST.
        !           418:             //
        !           419: 
        !           420:             //
        !           421:             // These are the initial value used.
        !           422:             //
        !           423:             // For now the "Max" values default to 0 (no limit).
        !           424:             //
        !           425: 
        !           426:             ConfigurationInfo->InitRequests = 15;
        !           427:             ConfigurationInfo->InitConnections = 3;
        !           428:             ConfigurationInfo->InitAddressFiles = 2;
        !           429:             ConfigurationInfo->InitAddresses = 2;
        !           430: 
        !           431:             //
        !           432:             // These are the initial values; remember that the
        !           433:             // resources above also allocate some of these each
        !           434:             // time they are allocated (shown in the comment).
        !           435:             //
        !           436: 
        !           437:             ConfigurationInfo->InitPackets = 75;         // + link + conn
        !           438:             ConfigurationInfo->InitReceivePackets = 25;  // + link + addr
        !           439:             ConfigurationInfo->InitReceiveBuffers = 20;  // + addr
        !           440: 
        !           441:             //
        !           442:             // Set the size of the packet pools and the total
        !           443:             // allocateable by ST.
        !           444:             //
        !           445: 
        !           446:             ConfigurationInfo->SendPacketPoolSize = 500;
        !           447:             ConfigurationInfo->ReceivePacketPoolSize = 200;
        !           448:             ConfigurationInfo->MaxMemoryUsage = 0;       // no limit
        !           449: 
        !           450:             break;
        !           451: 
        !           452:         default:
        !           453: 
        !           454:             ASSERT(FALSE);
        !           455:             break;
        !           456: 
        !           457:     }
        !           458: 
        !           459: 
        !           460:     //
        !           461:     // Now read the optional "hidden" parameters; if these do
        !           462:     // not exist then the current values are used. Note that
        !           463:     // the current values will be 0 unless they have been
        !           464:     // explicitly initialized above.
        !           465:     //
        !           466:     // NOTE: These macros expect "ConfigurationInfo" and
        !           467:     // "ParametersHandle" to exist when they are expanded.
        !           468:     //
        !           469: 
        !           470:     READ_HIDDEN_CONFIG (InitRequests);
        !           471:     READ_HIDDEN_CONFIG (InitConnections);
        !           472:     READ_HIDDEN_CONFIG (InitAddressFiles);
        !           473:     READ_HIDDEN_CONFIG (InitAddresses);
        !           474: 
        !           475:     READ_HIDDEN_CONFIG (MaxRequests);
        !           476:     READ_HIDDEN_CONFIG (MaxConnections);
        !           477:     READ_HIDDEN_CONFIG (MaxAddressFiles);
        !           478:     READ_HIDDEN_CONFIG (MaxAddresses);
        !           479: 
        !           480:     READ_HIDDEN_CONFIG (InitPackets);
        !           481:     READ_HIDDEN_CONFIG (InitReceivePackets);
        !           482:     READ_HIDDEN_CONFIG (InitReceiveBuffers);
        !           483: 
        !           484:     READ_HIDDEN_CONFIG (SendPacketPoolSize);
        !           485:     READ_HIDDEN_CONFIG (ReceivePacketPoolSize);
        !           486:     READ_HIDDEN_CONFIG (MaxMemoryUsage);
        !           487: 
        !           488: 
        !           489:     //
        !           490:     // Now that we are completely configured, save the information
        !           491:     // in the registry.
        !           492:     //
        !           493: 
        !           494:     StSaveConfigInRegistry (ParametersHandle, ConfigurationInfo);
        !           495: 
        !           496:     ExFreePool (RegistryPathBuffer);
        !           497:     StCloseParametersKey (ParametersHandle);
        !           498:     ZwClose (StConfigHandle);
        !           499: 
        !           500:     return STATUS_SUCCESS;
        !           501: 
        !           502: }   /* StConfigureTransport */
        !           503: 
        !           504: 
        !           505: VOID
        !           506: StFreeConfigurationInfo (
        !           507:     IN PCONFIG_DATA ConfigurationInfo
        !           508:     )
        !           509: 
        !           510: /*++
        !           511: 
        !           512: Routine Description:
        !           513: 
        !           514:     This routine is called by ST to get free any storage that was allocated
        !           515:     by StConfigureTransport in producing the specified CONFIG_DATA structure.
        !           516: 
        !           517: Arguments:
        !           518: 
        !           519:     ConfigurationInfo - A pointer to the configuration information structure.
        !           520: 
        !           521: Return Value:
        !           522: 
        !           523:     None.
        !           524: 
        !           525: --*/
        !           526: {
        !           527:     UINT i;
        !           528: 
        !           529:     for (i=0; i<ConfigurationInfo->NumAdapters; i++) {
        !           530:         RemoveAdapter (ConfigurationInfo, i);
        !           531:         RemoveDevice (ConfigurationInfo, i);
        !           532:     }
        !           533:     ExFreePool (ConfigurationInfo);
        !           534: 
        !           535: }   /* StFreeConfigurationInfo */
        !           536: 
        !           537: 
        !           538: NTSTATUS
        !           539: StOpenParametersKey(
        !           540:     IN HANDLE StConfigHandle,
        !           541:     OUT PHANDLE ParametersHandle
        !           542:     )
        !           543: 
        !           544: /*++
        !           545: 
        !           546: Routine Description:
        !           547: 
        !           548:     This routine is called by ST to open the ST "Parameters" key.
        !           549: 
        !           550: Arguments:
        !           551: 
        !           552:     ParametersHandle - Returns the handle used to read parameters.
        !           553: 
        !           554: Return Value:
        !           555: 
        !           556:     The status of the request.
        !           557: 
        !           558: --*/
        !           559: {
        !           560: 
        !           561:     NTSTATUS Status;
        !           562:     HANDLE ParamHandle;
        !           563:     PWSTR ParametersString = L"Parameters";
        !           564:     UNICODE_STRING ParametersKeyName;
        !           565:     OBJECT_ATTRIBUTES TmpObjectAttributes;
        !           566: 
        !           567:     //
        !           568:     // Open the ST parameters key.
        !           569:     //
        !           570: 
        !           571:     RtlInitUnicodeString (&ParametersKeyName, ParametersString);
        !           572: 
        !           573:     InitializeObjectAttributes(
        !           574:         &TmpObjectAttributes,
        !           575:         &ParametersKeyName,         // name
        !           576:         OBJ_CASE_INSENSITIVE,       // attributes
        !           577:         StConfigHandle,            // root
        !           578:         NULL                        // security descriptor
        !           579:         );
        !           580: 
        !           581: 
        !           582:     Status = ZwOpenKey(
        !           583:                  &ParamHandle,
        !           584:                  KEY_READ,
        !           585:                  &TmpObjectAttributes);
        !           586: 
        !           587:     if (!NT_SUCCESS(Status)) {
        !           588: 
        !           589:         StPrint1("Could not open parameters key: %lx\n", Status);
        !           590:         return Status;
        !           591: 
        !           592:     }
        !           593: 
        !           594:     *ParametersHandle = ParamHandle;
        !           595: 
        !           596: 
        !           597:     //
        !           598:     // All keys successfully opened or created.
        !           599:     //
        !           600: 
        !           601:     return STATUS_SUCCESS;
        !           602: 
        !           603: }   /* StOpenParametersKey */
        !           604: 
        !           605: VOID
        !           606: StCloseParametersKey(
        !           607:     IN HANDLE ParametersHandle
        !           608:     )
        !           609: 
        !           610: /*++
        !           611: 
        !           612: Routine Description:
        !           613: 
        !           614:     This routine is called by ST to close the "Parameters" key.
        !           615:     It closes the handles passed in and does any other work needed.
        !           616: 
        !           617: Arguments:
        !           618: 
        !           619:     ParametersHandle - The handle used to read other parameters.
        !           620: 
        !           621: Return Value:
        !           622: 
        !           623:     None.
        !           624: 
        !           625: --*/
        !           626: 
        !           627: {
        !           628: 
        !           629:     ZwClose (ParametersHandle);
        !           630: 
        !           631: }   /* StCloseParametersKey */
        !           632: 
        !           633: 
        !           634: NTSTATUS
        !           635: StCountEntries(
        !           636:     IN PWSTR ValueName,
        !           637:     IN ULONG ValueType,
        !           638:     IN PVOID ValueData,
        !           639:     IN ULONG ValueLength,
        !           640:     IN PVOID Context,
        !           641:     IN PVOID EntryContext
        !           642:     )
        !           643: 
        !           644: /*++
        !           645: 
        !           646: Routine Description:
        !           647: 
        !           648:     This routine is a callback routine for RtlQueryRegistryValues
        !           649:     It is called with the "Bind" and "Export" multi-strings.
        !           650:     It counts the number of name entries required in the
        !           651:     CONFIGURATION_DATA structure and then allocates it.
        !           652: 
        !           653: Arguments:
        !           654: 
        !           655:     ValueName - The name of the value ("Bind" or "Export" -- ignored).
        !           656: 
        !           657:     ValueType - The type of the value (REG_MULTI_SZ -- ignored).
        !           658: 
        !           659:     ValueData - The null-terminated data for the value.
        !           660: 
        !           661:     ValueLength - The length of ValueData (ignored).
        !           662: 
        !           663:     Context - A pointer to a pointer to the ConfigurationInfo structure.
        !           664:         When the "Export" callback is made this is filled in
        !           665:         with the allocate structure.
        !           666: 
        !           667:     EntryContext - A pointer to a counter holding the total number
        !           668:         of name entries required.
        !           669: 
        !           670: Return Value:
        !           671: 
        !           672:     STATUS_SUCCESS
        !           673: 
        !           674: --*/
        !           675: 
        !           676: {
        !           677:     ULONG StringCount;
        !           678:     PWCHAR ValuePointer = (PWCHAR)ValueData;
        !           679:     PCONFIG_DATA * ConfigurationInfo = (PCONFIG_DATA *)Context;
        !           680:     PULONG TotalCount = ((PULONG)EntryContext);
        !           681:     ULONG OldTotalCount = *TotalCount;
        !           682: 
        !           683:     ASSERT (ValueType == REG_MULTI_SZ);
        !           684: 
        !           685:     //
        !           686:     // Count the number of strings in the multi-string; first
        !           687:     // check that it is NULL-terminated to make the rest
        !           688:     // easier.
        !           689:     //
        !           690: 
        !           691:     if ((ValueLength < 2) ||
        !           692:         (ValuePointer[(ValueLength/2)-1] != (WCHAR)'\0')) {
        !           693:         return STATUS_INVALID_PARAMETER;
        !           694:     }
        !           695: 
        !           696:     StringCount = 0;
        !           697:     while (*ValuePointer != (WCHAR)'\0') {
        !           698:         while (*ValuePointer != (WCHAR)'\0') {
        !           699:             ++ValuePointer;
        !           700:         }
        !           701:         ++StringCount;
        !           702:         ++ValuePointer;
        !           703:         if ((ULONG)((PUCHAR)ValuePointer - (PUCHAR)ValueData) >= ValueLength) {
        !           704:             break;
        !           705:         }
        !           706:     }
        !           707: 
        !           708:     (*TotalCount) += StringCount;
        !           709: 
        !           710:     if (*ValueName == (WCHAR)'E') {
        !           711: 
        !           712:         //
        !           713:         // This is "Export", allocate the config data structure.
        !           714:         //
        !           715: 
        !           716:         *ConfigurationInfo = ExAllocatePool(
        !           717:                                  NonPagedPool,
        !           718:                                  sizeof (CONFIG_DATA) +
        !           719:                                      ((*TotalCount-1) * sizeof(NDIS_STRING)));
        !           720: 
        !           721:         if (*ConfigurationInfo == NULL) {
        !           722:             return STATUS_INSUFFICIENT_RESOURCES;
        !           723:         }
        !           724: 
        !           725:         RtlZeroMemory(
        !           726:             *ConfigurationInfo,
        !           727:             sizeof(CONFIG_DATA) + ((*TotalCount-1) * sizeof(NDIS_STRING)));
        !           728: 
        !           729:         (*ConfigurationInfo)->DevicesOffset = OldTotalCount;
        !           730: 
        !           731:     }
        !           732: 
        !           733:     return STATUS_SUCCESS;
        !           734: 
        !           735: }   /* StCountEntries */
        !           736: 
        !           737: 
        !           738: NTSTATUS
        !           739: StAddBind(
        !           740:     IN PWSTR ValueName,
        !           741:     IN ULONG ValueType,
        !           742:     IN PVOID ValueData,
        !           743:     IN ULONG ValueLength,
        !           744:     IN PVOID Context,
        !           745:     IN PVOID EntryContext
        !           746:     )
        !           747: 
        !           748: /*++
        !           749: 
        !           750: Routine Description:
        !           751: 
        !           752:     This routine is a callback routine for RtlQueryRegistryValues
        !           753:     It is called for each piece of the "Bind" multi-string and
        !           754:     saves the information in a ConfigurationInfo structure.
        !           755: 
        !           756: Arguments:
        !           757: 
        !           758:     ValueName - The name of the value ("Bind" -- ignored).
        !           759: 
        !           760:     ValueType - The type of the value (REG_SZ -- ignored).
        !           761: 
        !           762:     ValueData - The null-terminated data for the value.
        !           763: 
        !           764:     ValueLength - The length of ValueData (ignored).
        !           765: 
        !           766:     Context - A pointer to the ConfigurationInfo structure.
        !           767: 
        !           768:     EntryContext - A pointer to a count of binds that is incremented.
        !           769: 
        !           770: Return Value:
        !           771: 
        !           772:     STATUS_SUCCESS
        !           773: 
        !           774: --*/
        !           775: 
        !           776: {
        !           777:     PCONFIG_DATA ConfigurationInfo = *(PCONFIG_DATA *)Context;
        !           778:     PULONG CurBindNum = ((PULONG)EntryContext);
        !           779: 
        !           780:     UNREFERENCED_PARAMETER(ValueName);
        !           781:     UNREFERENCED_PARAMETER(ValueType);
        !           782:     UNREFERENCED_PARAMETER(ValueLength);
        !           783: 
        !           784:     InsertAdapter(
        !           785:         ConfigurationInfo,
        !           786:         *CurBindNum,
        !           787:         (PWSTR)(ValueData));
        !           788: 
        !           789:     ++(*CurBindNum);
        !           790: 
        !           791:     return STATUS_SUCCESS;
        !           792: 
        !           793: }   /* StAddBind */
        !           794: 
        !           795: 
        !           796: NTSTATUS
        !           797: StAddExport(
        !           798:     IN PWSTR ValueName,
        !           799:     IN ULONG ValueType,
        !           800:     IN PVOID ValueData,
        !           801:     IN ULONG ValueLength,
        !           802:     IN PVOID Context,
        !           803:     IN PVOID EntryContext
        !           804:     )
        !           805: 
        !           806: /*++
        !           807: 
        !           808: Routine Description:
        !           809: 
        !           810:     This routine is a callback routine for RtlQueryRegistryValues
        !           811:     It is called for each piece of the "Export" multi-string and
        !           812:     saves the information in a ConfigurationInfo structure.
        !           813: 
        !           814: Arguments:
        !           815: 
        !           816:     ValueName - The name of the value ("Export" -- ignored).
        !           817: 
        !           818:     ValueType - The type of the value (REG_SZ -- ignored).
        !           819: 
        !           820:     ValueData - The null-terminated data for the value.
        !           821: 
        !           822:     ValueLength - The length of ValueData (ignored).
        !           823: 
        !           824:     Context - A pointer to the ConfigurationInfo structure.
        !           825: 
        !           826:     EntryContext - A pointer to a count of exports that is incremented.
        !           827: 
        !           828: Return Value:
        !           829: 
        !           830:     STATUS_SUCCESS
        !           831: 
        !           832: --*/
        !           833: 
        !           834: {
        !           835:     PCONFIG_DATA ConfigurationInfo = *(PCONFIG_DATA *)Context;
        !           836:     PULONG CurExportNum = ((PULONG)EntryContext);
        !           837: 
        !           838:     UNREFERENCED_PARAMETER(ValueName);
        !           839:     UNREFERENCED_PARAMETER(ValueType);
        !           840:     UNREFERENCED_PARAMETER(ValueLength);
        !           841: 
        !           842:     InsertDevice(
        !           843:         ConfigurationInfo,
        !           844:         *CurExportNum,
        !           845:         (PWSTR)(ValueData));
        !           846: 
        !           847:     ++(*CurExportNum);
        !           848: 
        !           849:     return STATUS_SUCCESS;
        !           850: 
        !           851: }   /* StAddExport */
        !           852: 
        !           853: 
        !           854: VOID
        !           855: StReadLinkageInformation(
        !           856:     IN PWSTR RegistryPathBuffer,
        !           857:     IN PCONFIG_DATA * ConfigurationInfo
        !           858:     )
        !           859: 
        !           860: /*++
        !           861: 
        !           862: Routine Description:
        !           863: 
        !           864:     This routine is called by ST to read its linkage information
        !           865:     from the registry. If there is none present, then ConfigData
        !           866:     is filled with a list of all the adapters that are known
        !           867:     to ST.
        !           868: 
        !           869: Arguments:
        !           870: 
        !           871:     RegistryPathBuffer - The null-terminated root of the ST registry tree.
        !           872: 
        !           873:     ConfigurationInfo - Returns ST's current configuration.
        !           874: 
        !           875: Return Value:
        !           876: 
        !           877:     None.
        !           878: 
        !           879: --*/
        !           880: 
        !           881: {
        !           882: 
        !           883:     UINT ConfigBindings;
        !           884:     UINT NameCount = 0;
        !           885:     NTSTATUS Status;
        !           886:     RTL_QUERY_REGISTRY_TABLE QueryTable[6];
        !           887:     PWSTR Subkey = L"Linkage";
        !           888:     PWSTR Bind = L"Bind";
        !           889:     PWSTR Export = L"Export";
        !           890:     ULONG BindCount, ExportCount;
        !           891:     UINT i;
        !           892: 
        !           893: 
        !           894:     //
        !           895:     // Set up QueryTable to do the following:
        !           896:     //
        !           897: 
        !           898:     //
        !           899:     // 1) Switch to the Linkage key below ST
        !           900:     //
        !           901: 
        !           902:     QueryTable[0].QueryRoutine = NULL;
        !           903:     QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
        !           904:     QueryTable[0].Name = Subkey;
        !           905: 
        !           906:     //
        !           907:     // 2) Call StCountEntries for the "Bind" multi-string
        !           908:     //
        !           909: 
        !           910:     QueryTable[1].QueryRoutine = StCountEntries;
        !           911:     QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
        !           912:     QueryTable[1].Name = Bind;
        !           913:     QueryTable[1].EntryContext = (PVOID)&NameCount;
        !           914:     QueryTable[1].DefaultType = REG_NONE;
        !           915: 
        !           916:     //
        !           917:     // 3) Call StCountEntries for the "Export" multi-string
        !           918:     //
        !           919: 
        !           920:     QueryTable[2].QueryRoutine = StCountEntries;
        !           921:     QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
        !           922:     QueryTable[2].Name = Export;
        !           923:     QueryTable[2].EntryContext = (PVOID)&NameCount;
        !           924:     QueryTable[2].DefaultType = REG_NONE;
        !           925: 
        !           926:     //
        !           927:     // 4) Call StAddBind for each string in "Bind"
        !           928:     //
        !           929: 
        !           930:     QueryTable[3].QueryRoutine = StAddBind;
        !           931:     QueryTable[3].Flags = 0;
        !           932:     QueryTable[3].Name = Bind;
        !           933:     QueryTable[3].EntryContext = (PVOID)&BindCount;
        !           934:     QueryTable[3].DefaultType = REG_NONE;
        !           935: 
        !           936:     //
        !           937:     // 5) Call StAddExport for each string in "Export"
        !           938:     //
        !           939: 
        !           940:     QueryTable[4].QueryRoutine = StAddExport;
        !           941:     QueryTable[4].Flags = 0;
        !           942:     QueryTable[4].Name = Export;
        !           943:     QueryTable[4].EntryContext = (PVOID)&ExportCount;
        !           944:     QueryTable[4].DefaultType = REG_NONE;
        !           945: 
        !           946:     //
        !           947:     // 6) Stop
        !           948:     //
        !           949: 
        !           950:     QueryTable[5].QueryRoutine = NULL;
        !           951:     QueryTable[5].Flags = 0;
        !           952:     QueryTable[5].Name = NULL;
        !           953: 
        !           954: 
        !           955:     BindCount = 0;
        !           956:     ExportCount = 0;
        !           957: 
        !           958:     Status = RtlQueryRegistryValues(
        !           959:                  RTL_REGISTRY_ABSOLUTE,
        !           960:                  RegistryPathBuffer,
        !           961:                  QueryTable,
        !           962:                  (PVOID)ConfigurationInfo,
        !           963:                  NULL);
        !           964: 
        !           965:     if (Status != STATUS_SUCCESS) {
        !           966:         return;
        !           967:     }
        !           968: 
        !           969:     //
        !           970:     // Make sure that BindCount and ExportCount match, if not
        !           971:     // remove the extras.
        !           972:     //
        !           973: 
        !           974:     if (BindCount < ExportCount) {
        !           975: 
        !           976:         for (i=BindCount; i<ExportCount; i++) {
        !           977:             RemoveDevice (*ConfigurationInfo, i);
        !           978:         }
        !           979:         ConfigBindings = BindCount;
        !           980: 
        !           981:     } else if (ExportCount < BindCount) {
        !           982: 
        !           983:         for (i=ExportCount; i<BindCount; i++) {
        !           984:             RemoveAdapter (*ConfigurationInfo, i);
        !           985:         }
        !           986:         ConfigBindings = ExportCount;
        !           987: 
        !           988:     } else {
        !           989: 
        !           990:         ConfigBindings = BindCount;      // which is equal to ExportCount
        !           991: 
        !           992:     }
        !           993: 
        !           994:     (*ConfigurationInfo)->NumAdapters = ConfigBindings;
        !           995: 
        !           996: }   /* StReadLinkageInformation */
        !           997: 
        !           998: 
        !           999: UINT
        !          1000: StReadSizeInformation(
        !          1001:     IN HANDLE ParametersHandle
        !          1002:     )
        !          1003: 
        !          1004: /*++
        !          1005: 
        !          1006: Routine Description:
        !          1007: 
        !          1008:     This routine is called by ST to read the Size information
        !          1009:     from the registry.
        !          1010: 
        !          1011: Arguments:
        !          1012: 
        !          1013:     RegistryHandle - A pointer to the open registry.
        !          1014: 
        !          1015: Return Value:
        !          1016: 
        !          1017:     0 - no Size specified
        !          1018:     1 - Small
        !          1019:     2 - Medium
        !          1020:     3 - Big / Large
        !          1021: 
        !          1022: --*/
        !          1023: 
        !          1024: {
        !          1025: 
        !          1026:     UINT SizeToReturn;
        !          1027: //  STRING KeywordName;
        !          1028: //  PCONFIG_KEYWORD Keyword;
        !          1029: 
        !          1030:     ULONG InformationBuffer[16];   // declare ULONG to get it aligned
        !          1031:     PKEY_VALUE_FULL_INFORMATION Information =
        !          1032:         (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
        !          1033:     ULONG InformationLength;
        !          1034:     WCHAR SizeString[] = L"Size";
        !          1035:     UNICODE_STRING SizeValueName;
        !          1036:     NTSTATUS Status;
        !          1037:     PUCHAR InformationData;
        !          1038:     ULONG InformationLong;
        !          1039: 
        !          1040: 
        !          1041:     //
        !          1042:     // Read the size parameter out of the registry.
        !          1043:     //
        !          1044: 
        !          1045:     RtlInitUnicodeString (&SizeValueName, SizeString);
        !          1046: 
        !          1047:     Status = ZwQueryValueKey(
        !          1048:                  ParametersHandle,
        !          1049:                  &SizeValueName,
        !          1050:                  KeyValueFullInformation,
        !          1051:                  (PVOID)Information,
        !          1052:                  sizeof (InformationBuffer),
        !          1053:                  &InformationLength);
        !          1054: 
        !          1055:     //
        !          1056:     // Compare to the expected values.
        !          1057:     //
        !          1058: 
        !          1059:     if (Status == STATUS_SUCCESS) {
        !          1060: 
        !          1061:         InformationData = ((PUCHAR)Information) + Information->DataOffset;
        !          1062:         InformationLong = *((PULONG)InformationData);
        !          1063: 
        !          1064:         if ((Information->DataLength == sizeof(ULONG)) &&
        !          1065:             (InformationLong >= 1 && InformationLong <= 3)) {
        !          1066: 
        !          1067:             SizeToReturn = InformationLong;
        !          1068: 
        !          1069:         } else {
        !          1070: 
        !          1071:             if ((Information->DataLength >= 10) &&
        !          1072:                     (RtlCompareMemory (StrLarge, InformationData, 10) == 10)) {
        !          1073: 
        !          1074:                 SizeToReturn = 3;
        !          1075: 
        !          1076:             } else if ((Information->DataLength >= 12) &&
        !          1077:                     (RtlCompareMemory (StrMedium, InformationData, 12) == 12)) {
        !          1078: 
        !          1079:                 SizeToReturn = 2;
        !          1080: 
        !          1081:             } else if ((Information->DataLength >= 10) &&
        !          1082:                     (RtlCompareMemory (StrSmall, InformationData, 10) == 10)) {
        !          1083: 
        !          1084:                 SizeToReturn = 1;
        !          1085: 
        !          1086:             } else {
        !          1087: 
        !          1088:                 SizeToReturn = 0;
        !          1089: 
        !          1090:             }
        !          1091: 
        !          1092:         }
        !          1093: 
        !          1094:     } else {
        !          1095: 
        !          1096:         SizeToReturn = 0;
        !          1097: 
        !          1098:     }
        !          1099: 
        !          1100:     return SizeToReturn;
        !          1101: 
        !          1102: }   /* StReadSizeInformation */
        !          1103: 
        !          1104: 
        !          1105: ULONG
        !          1106: StReadSingleParameter(
        !          1107:     IN HANDLE ParametersHandle,
        !          1108:     IN PWCHAR ValueName,
        !          1109:     IN ULONG DefaultValue
        !          1110:     )
        !          1111: 
        !          1112: /*++
        !          1113: 
        !          1114: Routine Description:
        !          1115: 
        !          1116:     This routine is called by ST to read a single parameter
        !          1117:     from the registry. If the parameter is found it is stored
        !          1118:     in Data.
        !          1119: 
        !          1120: Arguments:
        !          1121: 
        !          1122:     ParametersHandle - A pointer to the open registry.
        !          1123: 
        !          1124:     ValueName - The name of the value to search for.
        !          1125: 
        !          1126:     DefaultValue - The default value.
        !          1127: 
        !          1128: Return Value:
        !          1129: 
        !          1130:     The value to use; will be the default if the value is not
        !          1131:     found or is not in the correct range.
        !          1132: 
        !          1133: --*/
        !          1134: 
        !          1135: {
        !          1136:     ULONG InformationBuffer[16];   // declare ULONG to get it aligned
        !          1137:     PKEY_VALUE_FULL_INFORMATION Information =
        !          1138:         (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
        !          1139:     UNICODE_STRING ValueKeyName;
        !          1140:     ULONG InformationLength;
        !          1141:     ULONG ReturnValue;
        !          1142:     NTSTATUS Status;
        !          1143: 
        !          1144:     RtlInitUnicodeString (&ValueKeyName, ValueName);
        !          1145: 
        !          1146:     Status = ZwQueryValueKey(
        !          1147:                  ParametersHandle,
        !          1148:                  &ValueKeyName,
        !          1149:                  KeyValueFullInformation,
        !          1150:                  (PVOID)Information,
        !          1151:                  sizeof (InformationBuffer),
        !          1152:                  &InformationLength);
        !          1153: 
        !          1154:     if ((Status == STATUS_SUCCESS) && (Information->DataLength == sizeof(ULONG))) {
        !          1155: 
        !          1156:         RtlCopyMemory(
        !          1157:             (PVOID)&ReturnValue,
        !          1158:             ((PUCHAR)Information) + Information->DataOffset,
        !          1159:             sizeof(ULONG));
        !          1160: 
        !          1161:         if (ReturnValue < 0) {
        !          1162: 
        !          1163:             ReturnValue = DefaultValue;
        !          1164: 
        !          1165:         }
        !          1166: 
        !          1167:     } else {
        !          1168: 
        !          1169:         ReturnValue = DefaultValue;
        !          1170: 
        !          1171:     }
        !          1172: 
        !          1173:     return ReturnValue;
        !          1174: 
        !          1175: }   /* StReadSingleParameter */
        !          1176: 
        !          1177: 
        !          1178: VOID
        !          1179: StWriteSingleParameter(
        !          1180:     IN HANDLE ParametersHandle,
        !          1181:     IN PWCHAR ValueName,
        !          1182:     IN ULONG ValueData
        !          1183:     )
        !          1184: 
        !          1185: /*++
        !          1186: 
        !          1187: Routine Description:
        !          1188: 
        !          1189:     This routine is called by ST to write a single parameter
        !          1190:     from the registry.
        !          1191: 
        !          1192: Arguments:
        !          1193: 
        !          1194:     ParametersHandle - A pointer to the open registry.
        !          1195: 
        !          1196:     ValueName - The name of the value to store.
        !          1197: 
        !          1198:     ValueData - The data to store at the value.
        !          1199: 
        !          1200: Return Value:
        !          1201: 
        !          1202:     None.
        !          1203: 
        !          1204: --*/
        !          1205: 
        !          1206: {
        !          1207:     UNICODE_STRING ValueKeyName;
        !          1208:     NTSTATUS Status;
        !          1209:     ULONG TmpValueData = ValueData;
        !          1210: 
        !          1211:     RtlInitUnicodeString (&ValueKeyName, ValueName);
        !          1212: 
        !          1213:     Status = ZwSetValueKey(
        !          1214:                  ParametersHandle,
        !          1215:                  &ValueKeyName,
        !          1216:                  0,
        !          1217:                  REG_DWORD,
        !          1218:                  (PVOID)&TmpValueData,
        !          1219:                  sizeof(ULONG));
        !          1220: 
        !          1221:     if (!NT_SUCCESS(Status)) {
        !          1222:         StPrint1("ST: Could not write dword key: %lx\n", Status);
        !          1223:     }
        !          1224: 
        !          1225: }   /* StWriteSingleParameter */
        !          1226: 
        !          1227: 
        !          1228: VOID
        !          1229: StSaveConfigInRegistry(
        !          1230:     IN HANDLE ParametersHandle,
        !          1231:     IN PCONFIG_DATA ConfigurationInfo
        !          1232:     )
        !          1233: 
        !          1234: /*++
        !          1235: 
        !          1236: Routine Description:
        !          1237: 
        !          1238:     This routine is called by ST to save its configuraition
        !          1239:     information in the registry. It saves the information if
        !          1240:     the registry structure did not exist before this boot.
        !          1241: 
        !          1242: Arguments:
        !          1243: 
        !          1244:     ParametersHandle - The handle used to read other parameters.
        !          1245: 
        !          1246:     ConfigurationInfo - Describes ST's current configuration.
        !          1247: 
        !          1248: Return Value:
        !          1249: 
        !          1250:     None.
        !          1251: 
        !          1252: --*/
        !          1253: 
        !          1254: {
        !          1255: 
        !          1256:     //
        !          1257:     // Save the "hidden" parameters, these may not exist in
        !          1258:     // the registry.
        !          1259:     //
        !          1260:     // NOTE: These macros expect "ConfigurationInfo" and
        !          1261:     // "ParametersHandle" to exist when they are expanded.
        !          1262:     //
        !          1263: 
        !          1264:     //
        !          1265:     // Don't write the parameters that are set
        !          1266:     // based on Size, since otherwise these will overwrite
        !          1267:     // those values since hidden parameters are set up
        !          1268:     // after the Size-based configuration is done.
        !          1269:     //
        !          1270: 
        !          1271:     WRITE_HIDDEN_CONFIG (MaxRequests);
        !          1272:     WRITE_HIDDEN_CONFIG (MaxConnections);
        !          1273:     WRITE_HIDDEN_CONFIG (MaxAddressFiles);
        !          1274:     WRITE_HIDDEN_CONFIG (MaxAddresses);
        !          1275: 
        !          1276: }   /* StSaveConfigInRegistry */
        !          1277: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.