Changeset 28830 in vbox for trunk/src/VBox/HostDrivers/VBoxNetFlt/win
- Timestamp:
- Apr 27, 2010 2:05:25 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 60746
- Location:
- trunk/src/VBox/HostDrivers/VBoxNetFlt/win
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.c
r28800 r28830 1112 1112 1113 1113 /* using the pPacketQueueSG as an indicator that the packet queue is initialized */ 1114 RTSpinlockAcquire ((pInstance)->hSpinlock, &Tmp);1114 RTSpinlockAcquireNoInts((pInstance)->hSpinlock, &Tmp); 1115 1115 if(pWorker->pSG) 1116 1116 { 1117 1117 pSG = pWorker->pSG; 1118 1118 pWorker->pSG = NULL; 1119 RTSpinlockRelease ((pInstance)->hSpinlock, &Tmp);1119 RTSpinlockReleaseNoInts((pInstance)->hSpinlock, &Tmp); 1120 1120 KeSetEvent(&pWorker->KillEvent, 0, FALSE); 1121 1121 … … 1131 1131 else 1132 1132 { 1133 RTSpinlockRelease ((pInstance)->hSpinlock, &Tmp);1133 RTSpinlockReleaseNoInts((pInstance)->hSpinlock, &Tmp); 1134 1134 } 1135 1135 } … … 3023 3023 Assert(pThis->fDisconnectedFromHost); 3024 3024 Assert(!pThis->fRediscoveryPending); 3025 Assert( !pThis->fActive);3025 Assert(pThis->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE); 3026 3026 #ifndef VBOXNETADP 3027 3027 Assert(pAdapt->PTState.OpState == kVBoxNetDevOpState_Deinitialized); … … 3255 3255 //#endif 3256 3256 3257 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);3258 3257 3259 3258 /* 4. mark as connected */ 3259 RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp); 3260 3260 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false); 3261 3262 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 3261 RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp); 3263 3262 3264 3263 pAttachInfo->Status = VINF_SUCCESS; … … 3271 3270 /* 5. Report MAC address, promiscuousness and GSO capabilities. */ 3272 3271 /** @todo Keep these up to date, esp. the promiscuous mode bit. */ 3273 if (pThis->pSwitchPort) 3272 if ( pThis->pSwitchPort 3273 && vboxNetFltTryRetainBusyNotDisconnected(pThis)) 3274 3274 { 3275 3275 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr); … … 3280 3280 /** @todo We should be able to do pfnXmit at DISPATCH_LEVEL... */ 3281 3281 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */); 3282 vboxNetFltRelease(pThis, true /*fBusy*/); 3282 3283 } 3283 3284 return; -
trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.h
r28800 r28830 636 636 pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt); 637 637 638 RTSpinlockAcquire ((pNetFlt)->hSpinlock, &Tmp);639 if( !ASMAtomicUoReadBool(&(pNetFlt)->fActive))640 { 641 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);638 RTSpinlockAcquireNoInts((pNetFlt)->hSpinlock, &Tmp); 639 if(pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE) 640 { 641 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 642 642 return NULL; 643 643 } … … 645 645 if(!vboxNetFltWinDoReferenceDevice(pAdapt, &pAdapt->PTState)) 646 646 { 647 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);647 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 648 648 return NULL; 649 649 } … … 651 651 vboxNetFltRetain((pNetFlt), true /* fBusy */); 652 652 653 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);653 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 654 654 655 655 return pNetFlt; … … 660 660 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 661 661 662 RTSpinlockAcquire ((pNetFlt)->hSpinlock, &Tmp);662 RTSpinlockAcquireNoInts((pNetFlt)->hSpinlock, &Tmp); 663 663 #ifndef VBOXNETADP 664 664 if(!vboxNetFltWinDoReferenceDevices(pAdapt, &pAdapt->MPState, &pAdapt->PTState)) … … 667 667 #endif 668 668 { 669 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);669 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 670 670 *pbNetFltActive = false; 671 671 return false; 672 672 } 673 673 674 if( !ASMAtomicUoReadBool(&(pNetFlt)->fActive))674 if(pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE) 675 675 { 676 676 vboxNetFltWinReferenceModePassThru(pNetFlt); 677 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);677 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 678 678 *pbNetFltActive = false; 679 679 return true; … … 682 682 vboxNetFltRetain((pNetFlt), true /* fBusy */); 683 683 vboxNetFltWinReferenceModeNetFlt(pNetFlt); 684 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);684 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 685 685 686 686 *pbNetFltActive = true; … … 704 704 pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt); 705 705 706 RTSpinlockAcquire ((pNetFlt)->hSpinlock, &Tmp);707 if( !ASMAtomicUoReadBool(&(pNetFlt)->fActive))708 { 709 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);706 RTSpinlockAcquireNoInts((pNetFlt)->hSpinlock, &Tmp); 707 if(pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE) 708 { 709 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 710 710 return NULL; 711 711 } … … 713 713 if(!vboxNetFltWinDoIncReferenceDevice(pAdapt, &pAdapt->PTState, v)) 714 714 { 715 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);715 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 716 716 return NULL; 717 717 } … … 719 719 vboxNetFltRetain((pNetFlt), true /* fBusy */); 720 720 721 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);721 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 722 722 723 723 /* we have marked it as busy, so can do the res references outside the lock */ … … 742 742 } 743 743 744 RTSpinlockAcquire ((pNetFlt)->hSpinlock, &Tmp);744 RTSpinlockAcquireNoInts((pNetFlt)->hSpinlock, &Tmp); 745 745 #ifndef VBOXNETADP 746 746 if(!vboxNetFltWinDoIncReferenceDevices(pAdapt, &pAdapt->MPState, &pAdapt->PTState, v)) … … 749 749 #endif 750 750 { 751 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);751 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 752 752 *pbNetFltActive = false; 753 753 return false; 754 754 } 755 755 756 if( !ASMAtomicUoReadBool(&(pNetFlt)->fActive))756 if(pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE) 757 757 { 758 758 vboxNetFltWinIncReferenceModePassThru(pNetFlt, v); 759 759 760 RTSpinlockRelease ((pNetFlt)->hSpinlock, &Tmp);760 RTSpinlockReleaseNoInts((pNetFlt)->hSpinlock, &Tmp); 761 761 *pbNetFltActive = false; 762 762 return true; … … 767 767 vboxNetFltWinIncReferenceModeNetFlt(pNetFlt, v); 768 768 769 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);769 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 770 770 771 771 /* we have marked it as busy, so can do the res references outside the lock */ … … 833 833 } 834 834 835 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);835 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 836 836 #ifdef VBOX_NETFLT_ONDEMAND_BIND 837 837 if(vboxNetFltWinDoIncReferenceDevice(pAdapt, &pAdapt->PTState)) … … 842 842 #endif 843 843 { 844 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);844 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 845 845 return true; 846 846 } 847 847 848 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);848 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 849 849 return false; 850 850 } … … 854 854 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt); 855 855 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 856 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);856 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 857 857 #ifdef VBOX_NETFLT_ONDEMAND_BIND 858 858 if(vboxNetFltWinDoReferenceDevice(pAdapt, &pAdapt->PTState)) … … 863 863 #endif 864 864 { 865 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);865 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 866 866 return true; 867 867 } 868 868 869 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);869 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 870 870 return false; 871 871 } -
trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltMp-win.c
r28800 r28830 486 486 * fail any request comming later 487 487 */ 488 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);488 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 489 489 490 490 ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true); … … 494 494 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitializing); 495 495 496 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);496 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 497 497 498 498 vboxNetFltWinWaitDereference(&pAdapt->MPState); … … 1001 1001 * If the miniport below is binding, fail the request 1002 1002 */ 1003 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);1003 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 1004 1004 1005 1005 if (vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized) 1006 1006 { 1007 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1007 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1008 1008 Status = NDIS_STATUS_FAILURE; 1009 1009 break; … … 1017 1017 { 1018 1018 pAdapt->bQueuedRequest = TRUE; 1019 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1019 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1020 1020 Status = NDIS_STATUS_PENDING; 1021 1021 break; … … 1026 1026 if (pAdapt->bStandingBy == TRUE) 1027 1027 { 1028 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1028 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1029 1029 Status = NDIS_STATUS_FAILURE; 1030 1030 break; … … 1032 1032 pAdapt->bOutstandingRequests = TRUE; 1033 1033 1034 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1034 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1035 1035 if(Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt)) 1036 1036 { … … 1050 1050 vboxNetFltWinDereferenceAdapt(pAdapt); 1051 1051 1052 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);1052 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 1053 1053 pAdapt->bOutstandingRequests = FALSE; 1054 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1054 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1055 1055 break; 1056 1056 } … … 1346 1346 * If the miniport below is unbinding, fail the request 1347 1347 */ 1348 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);1348 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 1349 1349 if (vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized) 1350 1350 { 1351 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1351 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1352 1352 Status = NDIS_STATUS_FAILURE; 1353 1353 break; … … 1362 1362 { 1363 1363 pAdapt->bQueuedRequest = TRUE; 1364 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1364 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1365 1365 Status = NDIS_STATUS_PENDING; 1366 1366 break; … … 1371 1371 if (pAdapt->bStandingBy == TRUE) 1372 1372 { 1373 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1373 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1374 1374 Status = NDIS_STATUS_FAILURE; 1375 1375 break; … … 1377 1377 pAdapt->bOutstandingRequests = TRUE; 1378 1378 1379 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1379 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1380 1380 1381 1381 if(Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt)) … … 1413 1413 vboxNetFltWinDereferenceAdapt(pAdapt); 1414 1414 1415 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);1415 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 1416 1416 pAdapt->bOutstandingRequests = FALSE; 1417 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1417 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1418 1418 break; 1419 1419 } -
trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltPt-win.c
r28800 r28830 299 299 * fail any request comming later 300 300 */ 301 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);301 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 302 302 303 303 ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true); … … 332 332 333 333 334 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);334 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 335 335 336 336 if (CompleteRequest == TRUE) … … 583 583 { 584 584 PVBOXNETFLTINS pNetFltIf = PADAPT_2_PVBOXNETFLTINS(pAdapt); 585 Assert( !pNetFltIf->fActive);585 Assert(pNetFltIf->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE); 586 586 vboxNetFltWinDereferenceModePassThru(pNetFltIf); 587 587 vboxNetFltWinDereferenceAdapt(pAdapt); … … 613 613 if(pAdapt->fProcessingPacketFilter == VBOXNETFLT_PFP_NETFLT) 614 614 { 615 Assert(pNetFltIf-> fActive);615 Assert(pNetFltIf->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE); 616 616 if(Status == NDIS_STATUS_SUCCESS) 617 617 { … … 625 625 else if(pAdapt->fProcessingPacketFilter == VBOXNETFLT_PFP_PASSTHRU) 626 626 { 627 Assert( !pNetFltIf->fActive);627 Assert(pNetFltIf->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE); 628 628 629 629 if(Status == NDIS_STATUS_SUCCESS) … … 849 849 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL); 850 850 do{ 851 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);851 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 852 852 853 853 Assert(pAdapt->cReceivedPacketCount < MAX_RECEIVE_PACKET_ARRAY_SIZE); … … 893 893 } 894 894 } 895 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);895 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 896 896 } while(0); 897 897 … … 1089 1089 do 1090 1090 { 1091 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);1091 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 1092 1092 1093 1093 if (pAdapt->cReceivedPacketCount > 0) … … 1103 1103 pAdapt->cReceivedPacketCount = 0; 1104 1104 1105 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1105 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1106 1106 1107 1107 if(!bReturn) … … 1132 1132 1133 1133 /* we are here only in case pAdapt->cReceivedPacketCount == 0 */ 1134 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);1134 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 1135 1135 } while (FALSE); 1136 1136 } … … 2112 2112 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 2113 2113 2114 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);2114 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 2115 2115 2116 2116 if(pAdapt->bClosingAdapter) 2117 2117 { 2118 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2118 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2119 2119 Assert(0); 2120 2120 return false; … … 2122 2122 if (pAdapt->hBindingHandle == NULL) 2123 2123 { 2124 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2124 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2125 2125 Assert(0); 2126 2126 return false; … … 2128 2128 2129 2129 pAdapt->bClosingAdapter = true; 2130 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2130 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2131 2131 2132 2132 /* … … 2177 2177 * Set the Internal Device State, this blocks all new sends or receives 2178 2178 */ 2179 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);2179 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 2180 2180 2181 2181 vboxNetFltWinSetPowerState(&pAdapt->PTState, *pDeviceState); … … 2193 2193 pAdapt->bStandingBy = TRUE; 2194 2194 } 2195 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2195 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2196 2196 #ifndef VBOX_NETFLT_ONDEMAND_BIND 2197 2197 … … 2218 2218 * If the below miniport is going to low power state, complete the queued request 2219 2219 */ 2220 RTSpinlockAcquire (pNetFlt->hSpinlock, &Tmp);2220 RTSpinlockAcquireNoInts(pNetFlt->hSpinlock, &Tmp); 2221 2221 if (pAdapt->bQueuedRequest) 2222 2222 { 2223 2223 pAdapt->bQueuedRequest = FALSE; 2224 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2224 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2225 2225 vboxNetFltWinPtRequestComplete(pAdapt, &pAdapt->Request, NDIS_STATUS_FAILURE); 2226 2226 } 2227 2227 else 2228 2228 { 2229 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2229 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2230 2230 } 2231 2231 #endif … … 2255 2255 2256 2256 #ifdef VBOX_NETFLT_ONDEMAND_BIND 2257 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2257 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2258 2258 #else 2259 2259 /* … … 2268 2268 2269 2269 pAdapt->bOutstandingRequests = TRUE; 2270 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2270 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2271 2271 2272 2272 NdisRequest(&Status, … … 2284 2284 else 2285 2285 { 2286 RTSpinlockRelease (pNetFlt->hSpinlock, &Tmp);2286 RTSpinlockReleaseNoInts(pNetFlt->hSpinlock, &Tmp); 2287 2287 } 2288 2288
Note:
See TracChangeset
for help on using the changeset viewer.