/*++ Copyright(c) 1998,99 Microsoft Corporation Module Name: prot.c Abstract: Windows Load Balancing Service (WLBS) Driver - lower-level (protocol) layer of intermediate miniport Author: kyrilf --*/ #define NDIS50 1 #define NDIS51 1 #include #include "prot.h" #include "nic.h" #include "main.h" #include "util.h" #include "univ.h" #include "log.h" /* GLOBALS */ NTHALAPI KIRQL KeGetCurrentIrql(); static ULONG log_module_id = LOG_MODULE_PROT; /* PROCEDURES */ VOID Prot_bind ( /* PASSIVE_IRQL */ PNDIS_STATUS statusp, NDIS_HANDLE bind_handle, PNDIS_STRING device_name, PVOID reg_path, PVOID reserved) { NDIS_STATUS status; NDIS_STATUS error_status; PMAIN_CTXT ctxtp; ULONG ret; UINT medium_index; ULONG i; ULONG peek_size; ULONG tmp; ULONG xferred; ULONG needed; ULONG result; PNDIS_REQUEST request; MAIN_ACTION act; INT adapter_index; // ###### ramkrish for multiple nic support PMAIN_ADAPTER adapterp = NULL; /* WLBS 2.3 */ NDIS_HANDLE ctxt_handle; NDIS_HANDLE config_handle; PNDIS_CONFIGURATION_PARAMETER param; NDIS_STRING device_str = NDIS_STRING_CONST ("UpperBindings"); //DbgBreakPoint(); /* make sure we are not attempting to bind to ourselves */ UNIV_PRINT (("Prot_bind: binding to %ls", device_name -> Buffer)); //#if 0 adapter_index = Main_adapter_get (device_name -> Buffer); if (adapter_index != MAIN_ADAPTER_NOT_FOUND) { UNIV_PRINT (("Already bound to this device 0x%x", adapter_index)); *statusp = NDIS_STATUS_FAILURE; return; } adapter_index = Main_adapter_selfbind (device_name -> Buffer); if (adapter_index != MAIN_ADAPTER_NOT_FOUND) { UNIV_PRINT (("Attempting to bind to ourselves 0x%x", adapter_index)); *statusp = NDIS_STATUS_FAILURE; return; } adapter_index = Main_adapter_alloc (device_name -> Buffer); if (adapter_index == MAIN_ADAPTER_NOT_FOUND) { UNIV_PRINT (("Unable to allocate ctxt for adapter 0x%x", univ_adapters_count)); *statusp = NDIS_STATUS_FAILURE; return; } //#endif // adapter_index = 0; adapterp = &(univ_adapters [adapter_index]); // adapterp -> used = TRUE; UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); NdisAcquireSpinLock(& univ_bind_lock); adapterp -> bound = TRUE; NdisReleaseSpinLock(& univ_bind_lock); UNIV_PRINT (("Prot_bind: devicename: length %d max length %d", device_name -> Length, device_name -> MaximumLength)); /* copy the device name to be used for future reference */ //#if 0 tmp = device_name -> MaximumLength * sizeof (WCHAR); status = NdisAllocateMemoryWithTag (& (adapterp -> device_name), device_name -> MaximumLength, UNIV_POOL_TAG); if (status != NDIS_STATUS_SUCCESS) { NdisAcquireSpinLock(& univ_bind_lock); adapterp -> bound = FALSE; NdisReleaseSpinLock(& univ_bind_lock); Main_adapter_put (adapterp); UNIV_PRINT (("error allocating memory %d %x", tmp, status)); __LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, tmp, status); * statusp = status; return; } NdisMoveMemory (adapterp -> device_name, device_name -> Buffer, device_name -> Length); adapterp -> device_name_len = device_name -> MaximumLength; adapterp -> device_name [(device_name -> Length)/sizeof (WCHAR)] = UNICODE_NULL; //#endif /* if we failed to deallocate the context during unbind (both halt and unbind were not called for example) - do it now before allocating a new context */ /* SBH - I think the comment below is bogus... Let's find out. */ ASSERT (adapterp->ctxtp == NULL); #if 0 // This code has been commented out since inited is guaranteed to be reset at this point if (adapterp -> inited && adapterp -> ctxtp != NULL) { adapterp -> inited = FALSE; NdisReleaseSpinLock(& univ_bind_lock); Main_cleanup (adapterp -> ctxtp); NdisFreeMemory (adapterp -> ctxtp, sizeof (MAIN_CTXT), 0); adapterp -> ctxtp = NULL; if (adapterp -> device_name_len) { NdisFreeMemory (adapterp -> device_name, adapterp -> device_name_len, 0); adapterp -> device_name = NULL; adapterp -> device_name_len = 0; } } else NdisReleaseSpinLock(& univ_bind_lock); #endif /* allocate device context */ status = NdisAllocateMemoryWithTag (& (adapterp -> ctxtp), sizeof (MAIN_CTXT), UNIV_POOL_TAG); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error allocating memory %d %x", sizeof (MAIN_CTXT), status)); __LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, sizeof (MAIN_CTXT), status); __LOG_MSG (MSG_ERROR_BIND_FAIL, adapterp -> device_name); * statusp = status; if (adapterp -> device_name_len) { NdisFreeMemory (adapterp -> device_name, adapterp -> device_name_len, 0); adapterp -> device_name = NULL; adapterp -> device_name_len = 0; } NdisAcquireSpinLock(& univ_bind_lock); adapterp -> bound = FALSE; NdisReleaseSpinLock(& univ_bind_lock); Main_adapter_put (adapterp); return; } /* initialize context */ ctxtp = adapterp -> ctxtp; NdisZeroMemory (ctxtp, sizeof (MAIN_CTXT)); NdisAcquireSpinLock (& univ_bind_lock); ctxtp -> code = MAIN_CTXT_CODE; ctxtp -> bind_handle = bind_handle; ctxtp -> adapter_id = adapter_index; NdisReleaseSpinLock (& univ_bind_lock); NdisInitializeEvent (& ctxtp -> completion_event); NdisResetEvent (& ctxtp -> completion_event); /* bind to specified adapter */ ctxt_handle = (NDIS_HANDLE) ctxtp; NdisOpenAdapter (& status, & error_status, & ctxtp -> mac_handle, & medium_index, univ_medium_array, UNIV_NUM_MEDIUMS, univ_prot_handle, ctxtp, device_name, 0, NULL); /* if pending - wait for Prot_open_complete to set the completion event */ if (status == NDIS_STATUS_PENDING) { ret = NdisWaitEvent (& ctxtp -> completion_event, UNIV_WAIT_TIME); if (! ret) { UNIV_PRINT (("error waiting for event")); __LOG_MSG1 (MSG_ERROR_INTERNAL, MSG_NONE, status); * statusp = status; NdisFreeMemory (ctxtp, sizeof (MAIN_CTXT), 0); if (adapterp -> device_name_len) { NdisFreeMemory (adapterp -> device_name, adapterp -> device_name_len, 0); adapterp -> device_name = NULL; adapterp -> device_name_len = 0; } NdisAcquireSpinLock(& univ_bind_lock); adapterp -> bound = FALSE; NdisReleaseSpinLock(& univ_bind_lock); Main_adapter_put (adapterp); return; } status = ctxtp -> completion_status; } /* check binding status */ if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error openning adapter %x", status)); __LOG_MSG1 (MSG_ERROR_OPEN, device_name -> Buffer, status); /* If the failure was because the medium was not supported, log this. */ if (status == NDIS_STATUS_UNSUPPORTED_MEDIA) { UNIV_PRINT (("unsupported medium")); __LOG_MSG (MSG_ERROR_MEDIA, MSG_NONE); } * statusp = status; NdisFreeMemory (ctxtp, sizeof (MAIN_CTXT), 0); if (adapterp -> device_name_len) { NdisFreeMemory (adapterp -> device_name, adapterp -> device_name_len, 0); adapterp -> device_name = NULL; adapterp -> device_name_len = 0; } NdisAcquireSpinLock(& univ_bind_lock); adapterp -> bound = FALSE; NdisReleaseSpinLock(& univ_bind_lock); Main_adapter_put (adapterp); return; } ctxtp -> medium = univ_medium_array [medium_index]; /* V1.3.1b make sure that underlying adapter is of the supported medium */ if (ctxtp -> medium != NdisMedium802_3) { /* This should never happen because this error should be caught earlier by NdisOpenAdapter, but we'll put another check here just in case. */ UNIV_PRINT (("unsupported medium %d", ctxtp -> medium)); __LOG_MSG1 (MSG_ERROR_MEDIA, MSG_NONE, ctxtp -> medium); goto error; } /* Copy "WLBS Cluster " into the log string. We'll add the cluster IP address later. This is because in some failure paths, we try to print this out in an event log, but its empty, so the event log looks incomplete. True, it will not necessarily have the cluster IP address, but it will have something. */ wcscpy(ctxtp->log_msg_str, CVY_NAME_MULTI_NIC); /* V1.3.0b extract current MAC address from the NIC - note that main is not inited yet so we have to create a local action */ act . code = MAIN_ACTION_CODE; act . ctxtp = ctxtp; request = & act . op . request . req; act . op . request . xferred = & xferred; act . op . request . needed = & needed; request -> RequestType = NdisRequestQueryInformation; if (ctxtp -> medium == NdisMedium802_3) request -> DATA . QUERY_INFORMATION . Oid = OID_802_3_CURRENT_ADDRESS; request -> DATA . QUERY_INFORMATION . InformationBuffer = & ctxtp -> ded_mac_addr; request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (CVY_MAC_ADR); status = Prot_request (ctxtp, & act, FALSE); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error %x requesting station address %d %d", status, xferred, needed)); goto error; } /* V1.3.1b get MAC options */ request -> RequestType = NdisRequestQueryInformation; request -> DATA . QUERY_INFORMATION . Oid = OID_GEN_MAC_OPTIONS; request -> DATA . QUERY_INFORMATION . InformationBuffer = & result; request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (ULONG); status = Prot_request (ctxtp, & act, FALSE); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error %x requesting MAC options %d %d", status, xferred, needed)); goto error; } UNIV_PRINT(("Prot_request query mac options completed")); ctxtp -> mac_options = result; /* Make sure the 802.3 adapter supports dynamically changing the MAC address of the NIC. */ if (!(ctxtp -> mac_options & NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE)) { UNIV_PRINT (("unsupported network adapter MAC options %x", ctxtp -> mac_options)); __LOG_MSG (MSG_ERROR_DYNAMIC_MAC, MSG_NONE); goto error; } status = Params_init (ctxtp, univ_reg_path, adapterp -> device_name + 8, & (ctxtp -> params)); /* Now, cat the cluster IP address onto the log message string to complete it. */ wcscat(ctxtp->log_msg_str, ctxtp->params.cl_ip_addr); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error retrieving registry parameters %x", status)); ctxtp -> convoy_enabled = ctxtp -> params_valid = FALSE; } else { ctxtp -> convoy_enabled = ctxtp -> params_valid = TRUE; } /* V1.3.2b check if media is connected. some cards do not register disconnection - so use this as a hint. */ request -> RequestType = NdisRequestQueryInformation; request -> DATA . QUERY_INFORMATION . Oid = OID_GEN_MEDIA_CONNECT_STATUS; request -> DATA . QUERY_INFORMATION . InformationBuffer = & result; request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (ULONG); status = Prot_request (ctxtp, & act, FALSE); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error %x requesting media connection status %d %d", status, xferred, needed)); ctxtp -> media_connected = TRUE; } else { ctxtp -> media_connected = (result == NdisMediaStateConnected); UNIV_PRINT (("Media state - %s", result == NdisMediaStateConnected ? "CONNECTED" : "DISCONNECTED")); UNIV_PRINT(("Prot_request query media connect status completed")); } /* V1.3.2b figure out MTU of the medium */ request -> RequestType = NdisRequestQueryInformation; request -> DATA . QUERY_INFORMATION . Oid = OID_GEN_MAXIMUM_TOTAL_SIZE; request -> DATA . QUERY_INFORMATION . InformationBuffer = & result; request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (ULONG); status = Prot_request (ctxtp, & act, FALSE); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error %x requesting max frame size %d %d", status, xferred, needed)); ctxtp -> max_frame_size = CVY_MAX_FRAME_SIZE; } else { ctxtp -> max_frame_size = result; UNIV_PRINT(("Prot_request query oid gen max size completed")); } /* figure out maximum multicast list size */ request -> RequestType = NdisRequestQueryInformation; if (ctxtp -> medium == NdisMedium802_3) request -> DATA . QUERY_INFORMATION . Oid = OID_802_3_MAXIMUM_LIST_SIZE; request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (ULONG); request -> DATA . QUERY_INFORMATION . InformationBuffer = & ctxtp->max_mcast_list_size; status = Prot_request (ctxtp, & act, FALSE); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error %x setting multicast address %d %d", status, xferred, needed)); goto error; } UNIV_PRINT(("Prot_request query oid gen max list size completed")); /* initialize main context now */ status = Main_init (ctxtp); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error initializing main module %x", status)); goto error; } NdisAcquireSpinLock(& univ_bind_lock); adapterp -> inited = TRUE; NdisReleaseSpinLock(& univ_bind_lock); /* WLBS 2.3 start off by opening the config section and reading our instance which we want to export for this binding */ NdisOpenProtocolConfiguration (& status, & config_handle, reg_path); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error openning protocol configuration %x", status)); goto error; } NdisReadConfiguration (& status, & param, config_handle, & device_str, NdisParameterString); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error reading binding configuration %x", status)); goto error; } /* free up whatever params allocated and get a new string to fit the device name */ if (param -> ParameterData . StringData . Length >= sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR)) { UNIV_PRINT (("nic name string too big %d %d\n", param -> ParameterData . StringData . Length, sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR))); } NdisMoveMemory (ctxtp -> virtual_nic_name, param -> ParameterData . StringData . Buffer, param -> ParameterData . StringData . Length < sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR) ? param -> ParameterData . StringData . Length : sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR)); * (PWSTR) ((PCHAR) ctxtp -> virtual_nic_name + param -> ParameterData . StringData . Length) = L'\0' ; UNIV_PRINT (("read binding name %ls\n", ctxtp -> virtual_nic_name)); #if 0 { WCHAR reg_path [512]; wcscpy (reg_path, univ_reg_path); wcscat (reg_path, adapterp -> device_name + 8); UNIV_PRINT (("Prot_bind: write binding name to %ls", reg_path)); status = RtlWriteRegistryValue (RTL_REGISTRY_SERVICES, reg_path, CVY_NAME_VIRTUAL_NIC, REG_SZ, ctxtp -> params . virtual_nic_name, param -> ParameterData . StringData . Length + 2); if (status != STATUS_SUCCESS) { UNIV_PRINT (("error writing virtual NIC name %x", status)); } } #endif /* we should be all inited at this point! during announcement, Nic_init will be called and it will start ping timer */ /* announce ourselves to the protocol above */ UNIV_PRINT(("calling nic_announce")); status = Nic_announce (ctxtp); if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error announcing driver %x", status)); goto error; } UNIV_PRINT (("Prot_bind: bound to %ls with %x", device_name -> Buffer, ctxtp -> mac_handle)); /* at this point TCP/IP should have bound to us after we announced ourselves to it and we are all done binding to NDIS below - all set! */ if (! ctxtp -> convoy_enabled) LOG_MSG (MSG_ERROR_DISABLED, MSG_NONE); else { ctxtp -> convoy_enabled = ctxtp -> params . cluster_mode; if (ctxtp -> convoy_enabled) { WCHAR num [20]; Univ_ulong_to_str (ctxtp -> params . host_priority, num, 10); LOG_MSG (MSG_INFO_STARTED, num); } else LOG_MSG (MSG_INFO_STOPPED, MSG_NONE); } UNIV_PRINT (("Prot_bind: returning 0x%x", status)); * statusp = status; return; error: * statusp = status; Prot_unbind (& status, ctxtp, ctxtp); return; } /* end Prot_bind */ VOID Prot_unbind ( /* PASSIVE_IRQL */ PNDIS_STATUS statusp, NDIS_HANDLE adapter_handle, NDIS_HANDLE unbind_handle) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; NDIS_STATUS status = NDIS_STATUS_SUCCESS; PMAIN_ACTION actp; PMAIN_ADAPTER adapterp; INT adapter_index; UNIV_PRINT (("Prot_unbind: called %x", ctxtp)); UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapter_index = ctxtp -> adapter_id; adapterp = & (univ_adapters [adapter_index]); UNIV_ASSERT (adapterp -> code = MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); ctxtp -> unbind_handle = unbind_handle; if (ctxtp->out_request != NULL) { actp = ctxtp->out_request; ctxtp->out_request = NULL; Prot_request_complete(ctxtp, & actp->op.request.req, NDIS_STATUS_FAILURE); } /* unannounce the nic now if it was announced before */ status = Nic_unannounce (ctxtp); UNIV_PRINT (("Prot_unbind: unaunnounced %x", status)); /* if still bound (Prot_close was not called from Nic_halt) then close now */ status = Prot_close (adapterp); UNIV_PRINT (("Prot_unbind: closed %x", status)); /* ctxtp might be gone at this point! */ #if 0 if (adapterp -> device_name_len) { NdisFreeMemory (adapterp -> device_name, adapterp -> device_name_len, 0); adapterp -> device_name = NULL; adapterp -> device_name_len = 0; } #endif Main_adapter_put (adapterp); * statusp = status; UNIV_PRINT (("Prot_unbind: returning with status 0x%x", status)); return; } /* end Prot_unbind */ VOID Prot_open_complete ( /* PASSIVE_IRQL */ NDIS_HANDLE adapter_handle, NDIS_STATUS open_status, NDIS_STATUS error_status) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; UNIV_PRINT (("Prot_open_complete: called %x", ctxtp)); UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); ctxtp -> completion_status = open_status; NdisSetEvent (& ctxtp -> completion_event); } /* end Prot_open_complete */ VOID Prot_close_complete ( /* PASSIVE_IRQL */ NDIS_HANDLE adapter_handle, NDIS_STATUS status) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; UNIV_PRINT (("Prot_close_complete: called %x %x", ctxtp, status)); UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); ctxtp -> completion_status = status; NdisSetEvent (& ctxtp -> completion_event); } /* end Prot_close_complete */ VOID Prot_request_complete ( NDIS_HANDLE adapter_handle, PNDIS_REQUEST request, NDIS_STATUS status) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; PMAIN_ACTION actp; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); actp = CONTAINING_RECORD (request, MAIN_ACTION, op . request . req); UNIV_ASSERT (actp -> code == MAIN_ACTION_CODE); /* if request came from above - pass completion up */ ctxtp->requests_pending = FALSE; if (actp -> op . request . external) { actp -> status = status; Nic_request_complete (ctxtp -> prot_handle, actp); // Nic_sync_queue (ctxtp, Nic_request_complete, actp, TRUE); } /* handle internal request completion */ else { if (request -> RequestType == NdisRequestSetInformation) { * actp -> op . request . xferred = request -> DATA . SET_INFORMATION . BytesRead; * actp -> op . request . needed = request -> DATA . SET_INFORMATION . BytesNeeded; } else { * actp -> op . request . xferred = request -> DATA . QUERY_INFORMATION . BytesWritten; * actp -> op . request . needed = request -> DATA . QUERY_INFORMATION . BytesNeeded; } ctxtp -> completion_status = status; NdisSetEvent (& ctxtp -> completion_event); } } /* end Prot_request_complete */ #ifdef PERIODIC_RESET extern ULONG resetting; #endif VOID Prot_reset_complete ( NDIS_HANDLE adapter_handle, NDIS_STATUS status) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; // PMAIN_ACTION actp; PMAIN_ADAPTER adapterp; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp = & (univ_adapters [ctxtp -> adapter_id]); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); if (! adapterp -> inited) return; #ifdef PERIODIC_RESET if (resetting) { resetting = FALSE; return; } #endif /* actp = Main_action_get (ctxtp); if (actp == NULL) { UNIV_PRINT (("error allocating action")); return; } actp -> status = status; */ Nic_reset_complete (ctxtp, status); // Nic_sync_queue (ctxtp, Nic_reset_complete, actp, TRUE); } /* end Prot_reset_complete */ VOID Prot_send_complete ( NDIS_HANDLE adapter_handle, PNDIS_PACKET packet, NDIS_STATUS status) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; PNDIS_PACKET oldp; PNDIS_PACKET_STACK pktstk; BOOLEAN stack_left; PMAIN_PROTOCOL_RESERVED resp; LONG lock_value; PMAIN_ADAPTER adapterp; BOOLEAN set = FALSE; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp = & (univ_adapters [ctxtp -> adapter_id]); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); if (! adapterp -> inited) return; MAIN_RESP_FIELD(packet, stack_left, pktstk, resp, TRUE); if (resp -> type == MAIN_PACKET_TYPE_PING || resp -> type == MAIN_PACKET_TYPE_IGMP) { Main_send_done (ctxtp, packet, status); return; } if (resp -> type == MAIN_PACKET_TYPE_CTRL) { UNIV_PRINT (("Prot_send_complete: control packet send complete\n")); Main_packet_put (ctxtp, packet, TRUE, status); return; } UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_PASS, resp -> type); #if 0 /* this code is only needed for Prot_send - see comments in Prot_send */ /* atomically signal Prot_send that a send complete arrived in case it is still in progress; see Prot_send and associated problem */ lock_value = InterlockedDecrement (& resp -> data); UNIV_ASSERT_VAL (lock_value == 0 || lock_value == 1, lock_value); /* if lock value is 1 then Prot_send is still running and we will supply it with a return status so that it can complete synchronously; otherwise, Prot_send has completed and we must provide an asynchronous completion to the protocol */ if (lock_value == 1) { resp -> len = status; return; } #endif oldp = Main_packet_put (ctxtp, packet, TRUE, status); /* ###### actp = Main_action_get (ctxtp); if (actp == NULL) { UNIV_PRINT (("error allocating action")); */ /* make sure that we always signal resource availability even if we cannot get an action to post a Nic_send_complete. do it through Nic_send_resources_signal instead */ /* ###### if (ctxtp -> packets_exhausted) { ctxtp -> packets_exhausted = FALSE; Nic_sync_queue (ctxtp, Nic_send_resources_signal, ctxtp, TRUE); } return; } */ if (ctxtp -> packets_exhausted) { ctxtp -> packets_exhausted = FALSE; /* optimized out since Nic_send_complete will perform the same action as the Nic_send_resources_signal */ /* Nic_sync_queue (ctxtp, Nic_send_resources_signal, ctxtp, TRUE); */ } /* ###### actp -> status = status; actp -> op . send . packet = oldp; */ Nic_send_complete (ctxtp, status, oldp); // Nic_sync_queue (ctxtp, Nic_send_complete, actp, TRUE); } /* end Prot_send_complete */ NDIS_STATUS Prot_recv_indicate ( NDIS_HANDLE adapter_handle, NDIS_HANDLE recv_handle, PVOID head_buf, UINT head_len, PVOID look_buf, UINT look_len, UINT packet_len) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; // PMAIN_ACTION actp; NDIS_STATUS status; PNDIS_PACKET packet, newp; ULONG xferred; BOOLEAN accept = FALSE; PMAIN_ADAPTER adapterp; PNDIS_PACKET_STACK pktstk; BOOLEAN stack_left; PMAIN_PROTOCOL_RESERVED resp; LONG lock_value; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp = & (univ_adapters [ctxtp -> adapter_id]); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); // ###### ramkrish check: check whether the driver has been announced to tcpip before processing any packets if (! adapterp -> inited || ! adapterp -> announced) return NDIS_STATUS_NOT_ACCEPTED; /* fix netflex driver bug that reports bogus packet length to us */ UNIV_ASSERT_VAL2(packet_len <= ctxtp -> max_frame_size && look_len <= ctxtp -> max_frame_size, packet_len, look_len); CVY_CHECK_MAX(look_len, ctxtp->max_frame_size); CVY_CHECK_MAX(packet_len, ctxtp->max_frame_size); /* V1.1.2 do not accept frames if the card below is resetting */ if (ctxtp -> reset_state != MAIN_RESET_NONE) return NDIS_STATUS_NOT_ACCEPTED; ctxtp -> recv_indicated = TRUE; /* V1.3.2b - see if we need to handle this packet */ packet = Main_recv_indicate (ctxtp, recv_handle, look_buf, look_len, packet_len, head_buf, head_len, &accept); if (! accept) /* NT 5.1 - ramkrish */ { ctxtp -> recv_indicated = FALSE; return NDIS_STATUS_NOT_ACCEPTED; } /* transfer the rest of the data if required. note that we have to xfer entire packet due to bugs on some card drives that do not handle partial xfers */ if (packet != NULL) /* NT 5.1 - ramkrish */ { if (look_len < packet_len) { NdisTransferData (& status, ctxtp -> mac_handle, recv_handle, 0, packet_len, packet, & xferred); } else { xferred = 0; status = NDIS_STATUS_SUCCESS; } if (status != NDIS_STATUS_PENDING) Prot_transfer_complete (adapter_handle, packet, status, xferred); } else /* propagate indicates to the protocol - NT 5.1 - ramkrish */ { do { /* If a packet was indicated, then indicate the packet up to the protocols */ packet = NdisGetReceivedPacket (ctxtp -> mac_handle, recv_handle); if (packet != NULL) /* Then allocate a new packet and then pass it up as a packet recv, but marked with status resources. */ { newp = Main_packet_get (ctxtp, packet, FALSE, 0, 0); if (newp != NULL) { MAIN_RESP_FIELD(packet, stack_left, pktstk, resp, FALSE); resp -> data = 2; /* This is to ensure that Prot_return does not return this packet */ status = NDIS_GET_PACKET_STATUS(packet); NDIS_SET_PACKET_STATUS (newp, NDIS_STATUS_RESOURCES); Nic_recv_packet (ctxtp, newp); Main_packet_put (ctxtp, newp, FALSE, NDIS_GET_PACKET_STATUS (newp)); NDIS_SET_PACKET_STATUS (packet, status); break; } } /* Fall through if no packet was indicated or no packet could be allocated or no packet stack */ Nic_recv_indicate (ctxtp, recv_handle, head_buf, head_len, look_buf, look_len, packet_len); } while (FALSE); } return NDIS_STATUS_SUCCESS; #if 0 /* old code */ actp = Main_action_get (ctxtp); if (actp == NULL) { UNIV_PRINT (("error allocating action")); return NDIS_STATUS_NOT_ACgCEPTED; } actp -> op . indicate . recv_handle = recv_handle; actp -> op . indicate . head_buf = head_buf; actp -> op . indicate . head_len = head_len; actp -> op . indicate . look_buf = look_buf; actp -> op . indicate . look_len = look_len; actp -> op . indicate . packet_len = packet_len; if (! Nic_sync_queue (ctxtp, Nic_recv_indicate, actp, FALSE)) /* 1.2.1 */ { if (((PUCHAR) head_buf) [0] & 0x1) { UNIV_PRINT (("error delivering loopback to higher level protocol due to syncing problem")); } else { UNIV_PRINT (("error delivering receive indicate to higher level protocol due to syncing problem")); } Main_action_put (ctxtp, actp); return NDIS_STATUS_NOT_ACCEPTED; } /* Main_action_put will be called in Nic_recv_indicate */ return NDIS_STATUS_SUCCESS; #endif } /* end Prot_recv_indicate */ VOID Prot_recv_complete ( /* PASSIVE_IRQL */ NDIS_HANDLE adapter_handle) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; PLIST_ENTRY entryp; PMAIN_ADAPTER adapterp; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp = & (univ_adapters [ctxtp -> adapter_id]); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); if (! adapterp -> inited) return; if (! adapterp -> announced) return; /* process control queue if there is any work on it */ while (1) { PMAIN_ACTION actp; entryp = NdisInterlockedRemoveHeadList (& ctxtp -> rct_list, & ctxtp -> rct_lock); if (entryp == NULL) break; actp = CONTAINING_RECORD (entryp, MAIN_ACTION, link); UNIV_ASSERT (actp -> code == MAIN_ACTION_CODE); /* handle remote control request now */ Main_ctrl_recv (ctxtp, actp -> op . ctrl . packet); /* note un-optimized call since running at PASSIVE IRQL */ Main_action_put (ctxtp, actp); } Nic_recv_complete (ctxtp); // Nic_sync_queue (ctxtp, Nic_recv_complete, ctxtp, TRUE); } /* end Prot_recv_complete */ VOID Prot_transfer_complete ( NDIS_HANDLE adapter_handle, PNDIS_PACKET packet, NDIS_STATUS status, UINT xferred) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; PNDIS_PACKET oldp; PNDIS_PACKET_STACK pktstk; BOOLEAN stack_left; PMAIN_PROTOCOL_RESERVED resp; LONG lock_value; PNDIS_BUFFER bufp; PMAIN_ADAPTER adapterp; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp = & (univ_adapters [ctxtp -> adapter_id]); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); if (! adapterp -> inited) return; MAIN_RESP_FIELD (packet, stack_left, pktstk, resp, FALSE); /* #ps# */ if (resp -> type == MAIN_PACKET_TYPE_PING) { Main_xfer_done (ctxtp, packet, status, xferred); return; } UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_INDICATE || resp -> type == MAIN_PACKET_TYPE_CTRL || resp -> type == MAIN_PACKET_TYPE_TRANSFER, resp -> type); /* V2.0.6 */ /* Added code for NT 5.1 - ramkrish */ if (resp -> type == MAIN_PACKET_TYPE_TRANSFER) { if (status == NDIS_STATUS_SUCCESS) { PUCHAR hdrp, mac_hdrp, tcp_hdrp; ULONG len; USHORT sig, group; /* Parse the buffers and obtain the length and group information. * This is used to update the counters. */ hdrp = Main_frame_parse (ctxtp, packet, & mac_hdrp, 0, & tcp_hdrp, & len, & sig, & group, FALSE); if (hdrp) { resp -> len = len; /* 64-bit -- ramkrish */ resp -> group = group; } } oldp = Main_packet_put (ctxtp, packet, FALSE, status); Nic_transfer_complete (ctxtp, status, packet, xferred); return; } if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error transferring %x", status)); Main_packet_put (ctxtp, packet, FALSE, status); return; } /* V1.3.2b */ if ((UINT) resp -> data != xferred) { UNIV_PRINT (("did not xfer enough data %d %d\n", resp -> data, xferred)); Main_packet_put (ctxtp, packet, FALSE, NDIS_STATUS_FAILURE); return; } /* if some data was transferred - then replace partial buffer with full frame buffer. we had a partial buffer describing just the data portion, without media header for NdisTransferData call. protocols can't handle multiple linked buffers on receive, so we need to have one big one describing both media header and payload */ if (xferred > 0) { NdisUnchainBufferAtFront (packet, & bufp); bufp = ((PMAIN_BUFFER) resp -> miscp) -> full_bufp; NdisChainBufferAtFront (packet, bufp); } /* put control packets on control queue */ if (resp -> type == MAIN_PACKET_TYPE_CTRL) { PMAIN_ACTION actp; actp = Main_action_get (ctxtp); if (actp == NULL) { UNIV_PRINT (("error allocating action")); Main_packet_put (ctxtp, packet, TRUE, NDIS_STATUS_FAILURE); return; } actp -> op . ctrl . packet = packet; NdisAcquireSpinLock (& ctxtp -> rct_lock); InsertTailList (& ctxtp -> rct_list, & actp -> link); NdisReleaseSpinLock (& ctxtp -> rct_lock); return; } /* pass packet up. note signalling to decide who will dispose of the packet */ resp -> data = 2; // actp -> op . recv . packet = packet; Nic_recv_packet (ctxtp, packet); // Nic_sync_queue (ctxtp, Nic_recv_packet, actp, TRUE); lock_value = InterlockedDecrement (& resp -> data); UNIV_ASSERT_VAL (lock_value == 0 || lock_value == 1, lock_value); if (lock_value == 0) Main_packet_put (ctxtp, packet, FALSE, NDIS_STATUS_SUCCESS); #if 0 /* old code */ oldp = Main_packet_put (ctxtp, packet, FALSE, status); actp = Main_action_get (ctxtp); if (actp == NULL) { UNIV_PRINT (("error allocating action")); return; } actp -> status = status; actp -> op . transfer . packet = oldp; actp -> op . transfer . xferred = xferred; Nic_sync_queue (ctxtp, Nic_transfer_complete, actp, TRUE); #endif } /* end Prot_transfer_complete */ NDIS_STATUS Prot_PNP_handle ( NDIS_HANDLE adapter_handle, PNET_PNP_EVENT pnp_event) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; PNDIS_DEVICE_POWER_STATE device_state; NDIS_STATUS status = NDIS_STATUS_SUCCESS; IOCTL_CVY_BUF ioctl_buf; PMAIN_ACTION actp; /* can happen when first initializing */ switch (pnp_event -> NetEvent) { case NetEventSetPower: if (adapter_handle == NULL) return NDIS_STATUS_SUCCESS; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); device_state = (PNDIS_DEVICE_POWER_STATE) (pnp_event -> Buffer); UNIV_PRINT (("Nic_PNP_handle: NetEventSetPower %x", * device_state)); // If the specified device state is D0, then handle it first, // else notify the protocols first and then handle it. if (*device_state != NdisDeviceStateD0) { status = Nic_PNP_handle (ctxtp, pnp_event); } // // Is the protocol transitioning from an On (D0) state to an Low Power State (>D0) // If so, then set the standby_state Flag - (Block all incoming requests) // if (ctxtp->prot_pnp_state == NdisDeviceStateD0 && *device_state > NdisDeviceStateD0) { ctxtp->standby_state = TRUE; } // // If the protocol is transitioning from a low power state to ON (D0), then clear the standby_state flag // All incoming requests will be pended until the physical miniport turns ON. // if (ctxtp->prot_pnp_state > NdisDeviceStateD0 && *device_state == NdisDeviceStateD0) { ctxtp->standby_state = FALSE; } ctxtp -> prot_pnp_state = *device_state; /* if we are being sent to standby, block outstanding requests and sends */ if (*device_state > NdisDeviceStateD0) { /* sleep till outstanding sends complete */ while (1) { ULONG i; /* #ps# -- ramkrish */ while (1) { NDIS_STATUS status; ULONG count; status = NdisQueryPendingIOCount (ctxtp -> mac_handle, & count); if (status != NDIS_STATUS_SUCCESS || count == 0) break; Nic_sleep (10); } for (i = 0; i < ctxtp->num_send_packet_allocs; i++) { if (NdisPacketPoolUsage(ctxtp->send_pool_handle[i]) != 0) break; } if (i >= ctxtp->num_send_packet_allocs) break; Nic_sleep(10); } /* sleep till outstanding requests complete */ while (ctxtp->requests_pending) { Nic_sleep(10); } } else { if (ctxtp->out_request != NULL) { NDIS_STATUS status; actp = ctxtp->out_request; ctxtp->out_request = NULL; status = Prot_request(ctxtp, actp, actp->op.request.external); if (status != NDIS_STATUS_PENDING) Prot_request_complete(ctxtp, & actp->op.request.req, status); } } if (*device_state == NdisDeviceStateD0) { status = Nic_PNP_handle (ctxtp, pnp_event); } break; case NetEventReconfigure: UNIV_PRINT (("Nic_PNP_handle: NetEventReconfigure")); if (adapter_handle == NULL) // This happens if the device is being enabled through the device manager. { UNIV_PRINT (("Prot_PNP_handle: Enumerate protocol bindings")); NdisReEnumerateProtocolBindings (univ_prot_handle); return NDIS_STATUS_SUCCESS; } /* gets called when something changes in our setup from notify object */ UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); /* This IOCTL will actually ignore the VIP argument, but set it to a reasonable value anyway. */ Main_ctrl (ctxtp, IOCTL_CVY_RELOAD, & ioctl_buf, IOCTL_ALL_VIPS); status = Nic_PNP_handle (ctxtp, pnp_event); UNIV_PRINT (("Nic_PNP_handle: NetEventReconfigure done %d %x", ioctl_buf . ret_code, status)); break; case NetEventQueryPower: UNIV_PRINT (("Nic_PNP_handle: NetEventQueryPower")); if (adapter_handle == NULL) return NDIS_STATUS_SUCCESS; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); status = Nic_PNP_handle (ctxtp, pnp_event); break; case NetEventQueryRemoveDevice: UNIV_PRINT (("Nic_PNP_handle: NetEventQueryRemoveDevice")); if (adapter_handle == NULL) return NDIS_STATUS_SUCCESS; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); status = Nic_PNP_handle (ctxtp, pnp_event); break; case NetEventCancelRemoveDevice: UNIV_PRINT (("Nic_PNP_handle: NetEventCancelRemoveDevice")); if (adapter_handle == NULL) return NDIS_STATUS_SUCCESS; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); status = Nic_PNP_handle (ctxtp, pnp_event); break; case NetEventBindList: UNIV_PRINT (("Nic_PNP_handle: NetEventBindList")); if (adapter_handle == NULL) return NDIS_STATUS_SUCCESS; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); status = Nic_PNP_handle (ctxtp, pnp_event); break; case NetEventBindsComplete: UNIV_PRINT (("Nic_PNP_handle: NetEventBindComplete")); if (adapter_handle == NULL) return NDIS_STATUS_SUCCESS; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); status = Nic_PNP_handle (ctxtp, pnp_event); break; default: UNIV_PRINT (("Nic_PNP_handle: new event")); if (adapter_handle == NULL) return NDIS_STATUS_SUCCESS; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); status = Nic_PNP_handle (ctxtp, pnp_event); break; } return status; /* Always return NDIS_STATUS_SUCCESS or the return value of NdisIMNotifyPnPEvent */ } /* end Nic_PNP_handle */ VOID Prot_status ( NDIS_HANDLE adapter_handle, NDIS_STATUS status, PVOID stat_buf, UINT stat_len) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; // PMAIN_ACTION actp; KIRQL irql; PMAIN_ADAPTER adapterp; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp = & (univ_adapters [ctxtp -> adapter_id]); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); UNIV_PRINT(("Prot_status called for adapter %d for notification %d: inited=%d, announced=%d", ctxtp -> adapter_id, status, adapterp->inited, adapterp->announced)); if (! adapterp -> inited || ! adapterp -> announced) return; UNIV_PRINT (("STATUS %x", status)); switch (status) { case NDIS_STATUS_WAN_LINE_UP: UNIV_PRINT (("NDIS_STATUS_WAN_LINE_UP")); break; case NDIS_STATUS_WAN_LINE_DOWN: UNIV_PRINT (("NDIS_STATUS_WAN_LINE_DOWN")); break; case NDIS_STATUS_MEDIA_CONNECT: UNIV_PRINT (("NDIS_STATUS_MEDIA_CONNECT")); /* V1.3.2b */ ctxtp -> media_connected = TRUE; break; case NDIS_STATUS_MEDIA_DISCONNECT: UNIV_PRINT (("NDIS_STATUS_MEDIA_DISCONNECT")); /* V1.3.2b */ ctxtp -> media_connected = FALSE; break; case NDIS_STATUS_HARDWARE_LINE_UP: UNIV_PRINT (("NDIS_STATUS_HARDWARE_LINE_UP")); break; case NDIS_STATUS_HARDWARE_LINE_DOWN: UNIV_PRINT (("NDIS_STATUS_HARDWARE_LINE_DOWN")); break; case NDIS_STATUS_INTERFACE_UP: UNIV_PRINT (("NDIS_STATUS_INTERFACE_UP")); break; case NDIS_STATUS_INTERFACE_DOWN: UNIV_PRINT (("NDIS_STATUS_INTERFACE_DOWN")); break; /* V1.1.2 */ case NDIS_STATUS_RESET_START: UNIV_PRINT (("NDIS_STATUS_RESET_START")); ctxtp -> reset_state = MAIN_RESET_START; ctxtp -> recv_indicated = FALSE; break; case NDIS_STATUS_RESET_END: UNIV_PRINT (("NDIS_STATUS_RESET_END")); // apparently alteon adapter does not call status complete function, // so need to transition to none state here in order to prevent hangs //ctxtp -> reset_state = MAIN_RESET_END; ctxtp -> reset_state = MAIN_RESET_NONE; break; default: break; } if (! MAIN_PNP_DEV_ON(ctxtp)) return; /* ###### actp = Main_action_get (ctxtp); if (actp == NULL) { UNIV_PRINT (("error allocating action")); return; } actp -> status = status; actp -> op . status . buf = stat_buf; actp -> op . status . len = stat_len; */ Nic_status (ctxtp, status, stat_buf, stat_len); // Nic_sync_queue (ctxtp, Nic_status, actp, TRUE); } /* end Prot_status */ VOID Prot_status_complete ( NDIS_HANDLE adapter_handle) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; // PMAIN_ACTION actp; PMAIN_ADAPTER adapterp; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp = & (univ_adapters [ctxtp -> adapter_id]); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); if (! adapterp -> inited) return; /* V1.1.2 */ if (ctxtp -> reset_state == MAIN_RESET_END) { ctxtp -> reset_state = MAIN_RESET_NONE; UNIV_PRINT (("NDIS_STATUS_RESET_END completed")); } else if (ctxtp -> reset_state == MAIN_RESET_START) { ctxtp -> reset_state = MAIN_RESET_START_DONE; UNIV_PRINT (("NDIS_STATUS_RESET_START completed")); } if (! MAIN_PNP_DEV_ON(ctxtp)) return; /* ###### actp = Main_action_get (ctxtp); if (actp == NULL) { UNIV_PRINT (("error allocating action")); return; } */ Nic_status_complete (ctxtp); // Nic_sync_queue (ctxtp, Nic_status_complete, actp, TRUE); } /* end Prot_status_complete */ /* helpers for nic layer */ NDIS_STATUS Prot_close ( /* PASSIVE_IRQL */ PMAIN_ADAPTER adapterp ) { NDIS_STATUS status; ULONG ret; PMAIN_CTXT ctxtp; UNIV_PRINT (("Prot_close: called")); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); // UNIV_ASSERT (adapterp -> ctxtp == ctxtp); ctxtp = adapterp -> ctxtp; /* close binding */ NdisAcquireSpinLock(& univ_bind_lock); if ( ! adapterp -> bound || ctxtp->mac_handle == NULL) { /* cleanup only on the second time we are entering Prot_close, which is called by both Nic_halt and Prot_unbind. the last one to be called will cleanup the context since they both use it. if both do not get called, then it will be cleaned up by Prot_bind before allocating a new one of Init_unload before unloading the driver. */ if (adapterp -> inited) { UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp -> inited = FALSE; NdisReleaseSpinLock(& univ_bind_lock); Main_cleanup (ctxtp); NdisFreeMemory (ctxtp, sizeof (MAIN_CTXT), 0); adapterp -> ctxtp = NULL; if (adapterp -> device_name_len) { NdisFreeMemory (adapterp -> device_name, adapterp -> device_name_len, 0); adapterp -> device_name = NULL; adapterp -> device_name_len = 0; } } else NdisReleaseSpinLock(& univ_bind_lock); Main_adapter_put (adapterp); return NDIS_STATUS_SUCCESS; } UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp -> bound = FALSE; ctxtp -> convoy_enabled = FALSE; NdisReleaseSpinLock(& univ_bind_lock); LOG_MSG (MSG_INFO_STOPPED, MSG_NONE); NdisResetEvent (& ctxtp -> completion_event); NdisCloseAdapter (& status, ctxtp -> mac_handle); /* if pending - wait for Prot_close_complete to set the completion event */ if (status == NDIS_STATUS_PENDING) { ret = NdisWaitEvent (& ctxtp -> completion_event, UNIV_WAIT_TIME); if (! ret) { UNIV_PRINT (("error waiting for event")); LOG_MSG1 (MSG_ERROR_INTERNAL, MSG_NONE, status); return NDIS_STATUS_FAILURE; } status = ctxtp -> completion_status; } /* At this point,wait for all pending recvs to be completed and then return */ ctxtp -> mac_handle = NULL; ctxtp -> prot_handle = NULL; /* check binding status */ if (status != NDIS_STATUS_SUCCESS) { UNIV_PRINT (("error closing adapter %x", status)); LOG_MSG1 (MSG_ERROR_INTERNAL, MSG_NONE, status); } /* if nic level is not announced anymore - safe to remove context now */ NdisAcquireSpinLock(& univ_bind_lock); if (! adapterp -> announced || ctxtp -> prot_handle == NULL) { if (adapterp -> inited) { adapterp -> inited = FALSE; NdisReleaseSpinLock(& univ_bind_lock); Main_cleanup (ctxtp); NdisFreeMemory (ctxtp, sizeof (MAIN_CTXT), 0); adapterp -> ctxtp = NULL; if (adapterp -> device_name_len) { NdisFreeMemory (adapterp -> device_name, adapterp -> device_name_len, 0); adapterp -> device_name = NULL; adapterp -> device_name_len = 0; } } else NdisReleaseSpinLock(& univ_bind_lock); Main_adapter_put (adapterp); } else NdisReleaseSpinLock(& univ_bind_lock); UNIV_PRINT (("Prot_close: exiting")); return status; } /* end Prot_close */ NDIS_STATUS Prot_request ( PMAIN_CTXT ctxtp, PMAIN_ACTION actp, ULONG external) { NDIS_STATUS status; PNDIS_REQUEST request = & actp -> op . request . req; ULONG ret; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); /* V1.1.2 do not accept requests if the card below is resetting */ actp -> op . request . external = external; if (ctxtp -> unbind_handle) // Prot_unbind was called return NDIS_STATUS_FAILURE; // if the Protocol device state is OFF, then the IM driver cannot send the // request below and must pend it if (ctxtp->prot_pnp_state > NdisDeviceStateD0) { UNIV_ASSERT (ctxtp->out_request == NULL); ctxtp->out_request = actp; return NDIS_STATUS_PENDING; } NdisResetEvent (& ctxtp -> completion_event); ctxtp->requests_pending = TRUE; NdisRequest (& status, ctxtp -> mac_handle, request); /* if pending - wait for Prot_request_complete to set the completion event */ if (status != NDIS_STATUS_PENDING) { ctxtp->requests_pending = FALSE; } else if (! external) { ret = NdisWaitEvent (& ctxtp -> completion_event, UNIV_WAIT_TIME); if (! ret) { UNIV_PRINT (("error waiting for event")); LOG_MSG1 (MSG_ERROR_INTERNAL, MSG_NONE, status); status = NDIS_STATUS_FAILURE; return status; } status = ctxtp -> completion_status; } return status; } /* end Prot_request */ NDIS_STATUS Prot_reset ( PMAIN_CTXT ctxtp) { NDIS_STATUS status; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); NdisReset (& status, ctxtp -> mac_handle); return status; } /* end Prot_reset */ VOID Prot_packets_send ( PMAIN_CTXT ctxtp, PPNDIS_PACKET packets, UINT num_packets) { PNDIS_PACKET array [CVY_MAX_SEND_PACKETS]; PNDIS_PACKET filtered_array [CVY_MAX_SEND_PACKETS]; UINT count = 0, filtered_count = 0, i; NDIS_STATUS status; PNDIS_PACKET newp; LONG lock_value; PMAIN_ACTION actp; ULONG exhausted; PNDIS_PACKET_STACK pktstk; BOOLEAN stack_left; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); /* V1.1.2 do not accept frames if the card below is resetting */ if (ctxtp -> reset_state != MAIN_RESET_NONE || ! MAIN_PNP_DEV_ON(ctxtp)) { ctxtp -> cntr_xmit_err ++; status = NDIS_STATUS_FAILURE; goto fail; } /* ###### modified for a deserialized driver - ramkrish */ for (count = i = 0; count < (num_packets > CVY_MAX_SEND_PACKETS ? CVY_MAX_SEND_PACKETS : num_packets); count ++) { newp = Main_send (ctxtp, packets [count], & exhausted); if (newp == NULL) { /* if we ran out of packets - get out of the loop */ if (exhausted) { UNIV_PRINT (("error xlating packet")); ctxtp -> packets_exhausted = TRUE; break; } /* if packet was filtered out - set status to success to calm TCP/IP down and go on to the next one */ else { /* ###### filtered_... added for NT 5.1 deserialization - ramkrish */ // ctxtp -> sends_filtered ++; filtered_array [filtered_count] = packets [count]; filtered_count++; NDIS_SET_PACKET_STATUS (packets [count], NDIS_STATUS_SUCCESS); continue; } } // resp = MAIN_PROTOCOL_FIELD (newp); /* #ps# */ #if 0 /* do not need this since corresponding code was commented out in Prot_send_complete */ /* initalize value to 1 to force Prot_send_complete to deal with the packet */ resp -> data = 1; #endif /* mark packet as pending send */ NDIS_SET_PACKET_STATUS (packets [count], NDIS_STATUS_PENDING); array [i] = newp; i ++; } if (i > 0) NdisSendPackets (ctxtp -> mac_handle, array, i); /* ###### added for indicating the filtered packets in deserialization - ramkrish */ for (i = 0; i < filtered_count; i++) Nic_send_complete (ctxtp, NDIS_STATUS_SUCCESS, filtered_array [i]); fail: /* ###### the remaining packets cannot be handled, no space in the pending queue too */ for (i = count; i < num_packets; i++) { NDIS_SET_PACKET_STATUS (packets [i], NDIS_STATUS_FAILURE); Nic_send_complete (ctxtp, NDIS_STATUS_FAILURE, packets [i]); } #if 0 /* old code used in serialized driver - ramkrish */ status = NDIS_STATUS_RESOURCES; /* the following code has to be removed and the other packets have to be put in a queue */ fail: /* fill status field on all un-handled packets */ for (i = count; i < num_packets; i ++) NDIS_SET_PACKET_STATUS (packets [i], status); #endif } /* end Prot_packets_send */ INT Prot_packet_recv ( NDIS_HANDLE adapter_handle, PNDIS_PACKET packet) { PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle; PNDIS_PACKET newp; NDIS_STATUS status; PMAIN_PROTOCOL_RESERVED resp; LONG lock_value; PNDIS_PACKET_STACK pktstk; BOOLEAN stack_left; PMAIN_ADAPTER adapterp; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); adapterp = & (univ_adapters [ctxtp -> adapter_id]); UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE); UNIV_ASSERT (adapterp -> ctxtp == ctxtp); // ###### ramkrish check: check whether the driver has been announced to tcpip before processing any packets if (! adapterp -> inited || ! adapterp -> announced) return 0; /* V1.1.4 do not accept frames if the card below is resetting */ if (ctxtp -> reset_state != MAIN_RESET_NONE) return 0; /* figure out if we need to handle this packet */ newp = Main_recv (ctxtp, packet); if (newp == NULL) return 0; // resp = MAIN_PROTOCOL_FIELD (newp); MAIN_RESP_FIELD (newp, stack_left, pktstk, resp, FALSE); /* #ps# */ /* put control packets on control queue */ if (resp -> type == MAIN_PACKET_TYPE_CTRL) { PMAIN_ACTION actp; actp = Main_action_get (ctxtp); if (actp == NULL) { UNIV_PRINT (("error allocating action")); Main_packet_put (ctxtp, newp, TRUE, NDIS_STATUS_FAILURE); return 0; } actp -> op . ctrl . packet = newp; NdisAcquireSpinLock (& ctxtp -> rct_lock); InsertTailList (& ctxtp -> rct_list, & actp -> link); NdisReleaseSpinLock (& ctxtp -> rct_lock); /* packet has been copied into our buffers - can return 0 */ return 0; } UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_PASS, resp -> type); /* pass packet up. note signaling to figure out who will be disposing of the packet */ resp -> data = 2; /* ###### actp -> op . recv . packet = newp; */ Nic_recv_packet (ctxtp, newp); // Nic_sync_queue (ctxtp, Nic_recv_packet, actp, TRUE); lock_value = InterlockedDecrement (& resp -> data); UNIV_ASSERT_VAL (lock_value == 0 || lock_value == 1, lock_value); if (lock_value == 0) { Main_packet_put (ctxtp, newp, FALSE, NDIS_STATUS_SUCCESS); return 0; } return 1; } /* end Prot_packet_recv */ VOID Prot_return ( PMAIN_CTXT ctxtp, PNDIS_PACKET packet) { PNDIS_PACKET oldp; PMAIN_PROTOCOL_RESERVED resp; LONG lock_value; ULONG type; PNDIS_PACKET_STACK pktstk; BOOLEAN stack_left; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); // resp = MAIN_PROTOCOL_FIELD (packet); MAIN_RESP_FIELD (packet, stack_left, pktstk, resp, FALSE); /* #ps# */ /* check to see if we need to be disposing of this packet */ lock_value = InterlockedDecrement (& resp -> data); UNIV_ASSERT_VAL (lock_value == 0 || lock_value == 1, lock_value); if (lock_value == 1) return; /* resp will become invalid after the call to Main_packet_put. save type for assertion below */ type = resp -> type; oldp = Main_packet_put (ctxtp, packet, FALSE, NDIS_STATUS_SUCCESS); /* if oldp is NULL - this is our internal packet from recv_indicate path */ if (oldp != NULL) { UNIV_ASSERT_VAL (type == MAIN_PACKET_TYPE_PASS, type); NdisReturnPackets (& oldp, 1); } } /* end Prot_return */ /* ###### Added from old code for NT 5.1 - ramkrish */ NDIS_STATUS Prot_transfer ( PMAIN_CTXT ctxtp, NDIS_HANDLE recv_handle, PNDIS_PACKET packet, UINT offset, UINT len, PUINT xferred) { NDIS_STATUS status; PNDIS_PACKET newp; PMAIN_PROTOCOL_RESERVED resp; PNDIS_PACKET_STACK pktstk; BOOLEAN stack_left; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); /* V1.1.2 do not accept frames if the card below is resetting */ if (ctxtp -> reset_state != MAIN_RESET_NONE) return NDIS_STATUS_FAILURE; /* we are trying to prevent transfer requests from stale receive indicates that have been made to the protocol layer prior to the reset operation. we do not know what is the old inbound frame state and cannot expect to be able to carry out any transfers. */ if (! ctxtp -> recv_indicated) { UNIV_PRINT (("*** ERROR - STALE RECV AFTER RESET ***")); return NDIS_STATUS_FAILURE; } newp = Main_packet_get (ctxtp, packet, FALSE, 0, 0); if (newp == NULL) { UNIV_PRINT (("error xlating packet")); return NDIS_STATUS_RESOURCES; } /* ###### for NT 5.1 - ramkrish */ // resp = MAIN_PROTOCOL_FIELD (newp); /* #ps# */ MAIN_RESP_FIELD (newp, stack_left, pktstk, resp, FALSE); resp -> type = MAIN_PACKET_TYPE_TRANSFER; NdisTransferData (& status, ctxtp -> mac_handle, recv_handle, offset, len, newp, xferred); /* V1.1.2 */ if (status != NDIS_STATUS_PENDING) { if (status == NDIS_STATUS_SUCCESS) { PUCHAR hdrp, mac_hdrp, tcp_hdrp; ULONG len; USHORT sig, group; /* Parse the buffers and obtain the length and group information. * This is used to update the counters. */ hdrp = Main_frame_parse (ctxtp, newp, & mac_hdrp, 0, & tcp_hdrp, & len, & sig, & group, FALSE); if (hdrp) { resp -> len = len; resp -> group = group; } } Main_packet_put (ctxtp, newp, FALSE, status); } return status; } /* end Prot_transfer */ VOID Prot_cancel_send_packets ( PMAIN_CTXT ctxtp, PVOID cancel_id) { UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); NdisCancelSendPackets (ctxtp -> mac_handle, cancel_id); return; } /* Prot_cancel_send_packets */ #if 0 /* This code relies on using the len field in MAIN_PROTOCOL_RESERVED to hold the status value passed from Main_send_complete. Uncommenting it in this state will break! Note that setting and interlock decrementing of data field is commented out in Prot_packets_send and Prot_send_complete. */ NDIS_STATUS Prot_send ( PMAIN_CTXT ctxtp, PNDIS_PACKET packet, UINT flags) { NDIS_STATUS status; PNDIS_PACKET newp; PMAIN_PROTOCOL_RESERVED resp; LONG lock_value; ULONG exhausted; UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE); /* V1.1.2 do not accept frames if the card below is resetting */ if (ctxtp -> reset_state != MAIN_RESET_NONE) return NDIS_STATUS_FAILURE; newp = Main_send (ctxtp, packet, & exhausted); if (newp == NULL) { if (exhausted) { UNIV_PRINT (("error xlating packet")); ctxtp -> packets_exhausted = TRUE; return NDIS_STATUS_RESOURCES; } else return NDIS_STATUS_SUCCESS; } NdisSetPacketFlags (newp, flags); resp = MAIN_PROTOCOL_FIELD (newp); /* initialize lock value to 2 so that can distinguish whether or not send complete occurred during send to NDIS; see below */ resp -> data = 2; NdisSend (& status, ctxtp -> mac_handle, newp); /* atomically decrement and check lock value; Prot_send_complete also does this */ lock_value = InterlockedDecrement (& resp -> data); UNIV_ASSERT_VAL (lock_value == 0 || lock_value == 1, lock_value); /* if lock value is 1 then Prot_send_complete has not completed and it will later call Nic_send_complete and cleanup; otherwise, if lock value is 0, Prot_send_complete has run and supplied us with a status to return synchronously; this handles an apparent bug in which send complete is signalled during the send operation but the send returns a pending status anyway */ if (lock_value == 0) status = resp -> len; if (status != NDIS_STATUS_PENDING) { Main_packet_put (ctxtp, newp, TRUE, status); if (ctxtp -> packets_exhausted) { ctxtp -> packets_exhausted = FALSE; Nic_sync_queue (ctxtp, Nic_send_resources_signal, ctxtp, TRUE); } } return status; } /* end Prot_send */ #endif