00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00022 #include "config.h"
00023 #include <time.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026
00027 #include "pcscd.h"
00028 #include "winscard.h"
00029 #include "debuglog.h"
00030 #include "winscard_msg.h"
00031 #include "winscard_svc.h"
00032 #include "sys_generic.h"
00033 #include "thread_generic.h"
00034 #include "readerfactory.h"
00035
00041 static struct _psContext
00042 {
00043 SCARDCONTEXT hContext;
00044 SCARDHANDLE hCard[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS];
00045 DWORD dwClientID;
00046 PCSCLITE_THREAD_T pthThread;
00047 sharedSegmentMsg msgStruct;
00048 int protocol_major, protocol_minor;
00049 } psContext[PCSCLITE_MAX_APPLICATIONS_CONTEXTS];
00050
00051 LONG MSGCheckHandleAssociation(SCARDHANDLE, DWORD);
00052 LONG MSGFunctionDemarshall(psharedSegmentMsg, DWORD);
00053 LONG MSGAddContext(SCARDCONTEXT, DWORD);
00054 LONG MSGRemoveContext(SCARDCONTEXT, DWORD);
00055 LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, DWORD);
00056 LONG MSGRemoveHandle(SCARDHANDLE, DWORD);
00057 LONG MSGCleanupClient(DWORD);
00058
00059 static void ContextThread(LPVOID pdwIndex);
00060
00061 LONG ContextsInitialize(void)
00062 {
00063 memset(psContext, 0, sizeof(struct _psContext)*PCSCLITE_MAX_APPLICATIONS_CONTEXTS);
00064 return 1;
00065 }
00066
00077 LONG CreateContextThread(PDWORD pdwClientID)
00078 {
00079 int i;
00080
00081 for (i = 0; i < PCSCLITE_MAX_APPLICATIONS_CONTEXTS; i++)
00082 {
00083 if (psContext[i].dwClientID == 0)
00084 {
00085 psContext[i].dwClientID = *pdwClientID;
00086 *pdwClientID = 0;
00087 break;
00088 }
00089 }
00090
00091 if (i == PCSCLITE_MAX_APPLICATIONS_CONTEXTS)
00092 {
00093 Log2(PCSC_LOG_CRITICAL, "No more context available (max: %d)",
00094 PCSCLITE_MAX_APPLICATIONS_CONTEXTS);
00095 return SCARD_F_INTERNAL_ERROR;
00096 }
00097
00098 if (SYS_ThreadCreate(&psContext[i].pthThread, THREAD_ATTR_DETACHED,
00099 (PCSCLITE_THREAD_FUNCTION( )) ContextThread,
00100 (LPVOID) i) != 1)
00101 {
00102 SYS_CloseFile(psContext[i].dwClientID);
00103 psContext[i].dwClientID = 0;
00104 Log1(PCSC_LOG_CRITICAL, "SYS_ThreadCreate failed");
00105 return SCARD_E_NO_MEMORY;
00106 }
00107
00108 return SCARD_S_SUCCESS;
00109 }
00110
00111
00112
00113
00114
00115
00124 static void ContextThread(LPVOID dwIndex)
00125 {
00126 LONG rv;
00127 sharedSegmentMsg msgStruct;
00128 DWORD dwContextIndex = (DWORD)dwIndex;
00129
00130 Log2(PCSC_LOG_DEBUG, "Thread is started: %d",
00131 psContext[dwContextIndex].dwClientID);
00132
00133 while (1)
00134 {
00135 switch (rv = SHMProcessEventsContext(&psContext[dwContextIndex].dwClientID, &msgStruct, 0))
00136 {
00137 case 0:
00138 if (msgStruct.mtype == CMD_CLIENT_DIED)
00139 {
00140
00141
00142
00143 Log2(PCSC_LOG_DEBUG, "Client die: %d",
00144 psContext[dwContextIndex].dwClientID);
00145 MSGCleanupClient(dwContextIndex);
00146 SYS_ThreadExit((LPVOID) NULL);
00147 }
00148 break;
00149
00150 case 1:
00151 if (msgStruct.mtype == CMD_FUNCTION)
00152 {
00153
00154
00155
00156 MSGFunctionDemarshall(&msgStruct, dwContextIndex);
00157
00158
00159
00160 if ((msgStruct.command != SCARD_TRANSMIT_EXTENDED)
00161 && (msgStruct.command != SCARD_CONTROL_EXTENDED))
00162 rv = SHMMessageSend(&msgStruct, sizeof(msgStruct),
00163 psContext[dwContextIndex].dwClientID,
00164 PCSCLITE_SERVER_ATTEMPTS);
00165 }
00166 else
00167
00168 if (msgStruct.mtype == CMD_VERSION)
00169 {
00170 version_struct *veStr;
00171 veStr = (version_struct *) msgStruct.data;
00172
00173
00174 psContext[dwContextIndex].protocol_major = veStr->major;
00175 psContext[dwContextIndex].protocol_minor = veStr->minor;
00176
00177 Log3(PCSC_LOG_DEBUG,
00178 "Client is protocol version %d:%d",
00179 veStr->major, veStr->minor);
00180
00181 veStr->rv = SCARD_S_SUCCESS;
00182
00183
00184 if ((veStr->major > PROTOCOL_VERSION_MAJOR)
00185 || (veStr->major == PROTOCOL_VERSION_MAJOR
00186 && veStr->minor > PROTOCOL_VERSION_MINOR))
00187 {
00188 Log3(PCSC_LOG_CRITICAL,
00189 "Client protocol is too new %d:%d",
00190 veStr->major, veStr->minor);
00191 Log3(PCSC_LOG_CRITICAL,
00192 "Server protocol is %d:%d",
00193 PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR);
00194 veStr->rv = SCARD_E_NO_SERVICE;
00195 }
00196
00197
00198 veStr->major = PROTOCOL_VERSION_MAJOR;
00199 veStr->minor = PROTOCOL_VERSION_MINOR;
00200
00201
00202 rv = SHMMessageSend(&msgStruct, sizeof(msgStruct),
00203 psContext[dwContextIndex].dwClientID,
00204 PCSCLITE_SERVER_ATTEMPTS);
00205 }
00206 else
00207 continue;
00208
00209 break;
00210
00211 case 2:
00212
00213
00214
00215
00216
00217 break;
00218
00219 case -1:
00220 Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsContext");
00221 break;
00222
00223 default:
00224 Log2(PCSC_LOG_ERROR,
00225 "SHMProcessEventsContext unknown retval: %d", rv);
00226 break;
00227 }
00228 }
00229 }
00230
00246 LONG MSGFunctionDemarshall(psharedSegmentMsg msgStruct, DWORD dwContextIndex)
00247 {
00248 LONG rv;
00249 establish_struct *esStr;
00250 release_struct *reStr;
00251 connect_struct *coStr;
00252 reconnect_struct *rcStr;
00253 disconnect_struct *diStr;
00254 begin_struct *beStr;
00255 cancel_struct *caStr;
00256 end_struct *enStr;
00257 status_struct *stStr;
00258 transmit_struct *trStr;
00259 control_struct *ctStr;
00260 getset_struct *gsStr;
00261
00262
00263
00264
00265 rv = 0;
00266 switch (msgStruct->command)
00267 {
00268
00269 case SCARD_ESTABLISH_CONTEXT:
00270 esStr = ((establish_struct *) msgStruct->data);
00271 esStr->rv = SCardEstablishContext(esStr->dwScope, 0, 0,
00272 &esStr->phContext);
00273
00274 if (esStr->rv == SCARD_S_SUCCESS)
00275 esStr->rv =
00276 MSGAddContext(esStr->phContext, dwContextIndex);
00277 break;
00278
00279 case SCARD_RELEASE_CONTEXT:
00280 reStr = ((release_struct *) msgStruct->data);
00281 reStr->rv = SCardReleaseContext(reStr->hContext);
00282
00283 if (reStr->rv == SCARD_S_SUCCESS)
00284 reStr->rv =
00285 MSGRemoveContext(reStr->hContext, dwContextIndex);
00286
00287 break;
00288
00289 case SCARD_CONNECT:
00290 coStr = ((connect_struct *) msgStruct->data);
00291 coStr->rv = SCardConnect(coStr->hContext, coStr->szReader,
00292 coStr->dwShareMode, coStr->dwPreferredProtocols,
00293 &coStr->phCard, &coStr->pdwActiveProtocol);
00294
00295 if (coStr->rv == SCARD_S_SUCCESS)
00296 coStr->rv =
00297 MSGAddHandle(coStr->hContext, coStr->phCard, dwContextIndex);
00298
00299 break;
00300
00301 case SCARD_RECONNECT:
00302 rcStr = ((reconnect_struct *) msgStruct->data);
00303 rv = MSGCheckHandleAssociation(rcStr->hCard, dwContextIndex);
00304 if (rv != 0) return rv;
00305
00306 rcStr->rv = SCardReconnect(rcStr->hCard, rcStr->dwShareMode,
00307 rcStr->dwPreferredProtocols,
00308 rcStr->dwInitialization, &rcStr->pdwActiveProtocol);
00309 break;
00310
00311 case SCARD_DISCONNECT:
00312 diStr = ((disconnect_struct *) msgStruct->data);
00313 rv = MSGCheckHandleAssociation(diStr->hCard, dwContextIndex);
00314 if (rv != 0) return rv;
00315 diStr->rv = SCardDisconnect(diStr->hCard, diStr->dwDisposition);
00316
00317 if (diStr->rv == SCARD_S_SUCCESS)
00318 diStr->rv =
00319 MSGRemoveHandle(diStr->hCard, dwContextIndex);
00320 break;
00321
00322 case SCARD_BEGIN_TRANSACTION:
00323 beStr = ((begin_struct *) msgStruct->data);
00324 rv = MSGCheckHandleAssociation(beStr->hCard, dwContextIndex);
00325 if (rv != 0) return rv;
00326 beStr->rv = SCardBeginTransaction(beStr->hCard);
00327 break;
00328
00329 case SCARD_END_TRANSACTION:
00330 enStr = ((end_struct *) msgStruct->data);
00331 rv = MSGCheckHandleAssociation(enStr->hCard, dwContextIndex);
00332 if (rv != 0) return rv;
00333 enStr->rv =
00334 SCardEndTransaction(enStr->hCard, enStr->dwDisposition);
00335 break;
00336
00337 case SCARD_CANCEL_TRANSACTION:
00338 caStr = ((cancel_struct *) msgStruct->data);
00339 rv = MSGCheckHandleAssociation(caStr->hCard, dwContextIndex);
00340 if (rv != 0) return rv;
00341 caStr->rv = SCardCancelTransaction(caStr->hCard);
00342 break;
00343
00344 case SCARD_STATUS:
00345 stStr = ((status_struct *) msgStruct->data);
00346 rv = MSGCheckHandleAssociation(stStr->hCard, dwContextIndex);
00347 if (rv != 0) return rv;
00348 stStr->rv = SCardStatus(stStr->hCard, stStr->mszReaderNames,
00349 &stStr->pcchReaderLen, &stStr->pdwState,
00350 &stStr->pdwProtocol, stStr->pbAtr, &stStr->pcbAtrLen);
00351 break;
00352
00353 case SCARD_TRANSMIT:
00354 trStr = ((transmit_struct *) msgStruct->data);
00355 rv = MSGCheckHandleAssociation(trStr->hCard, dwContextIndex);
00356 if (rv != 0) return rv;
00357 trStr->rv = SCardTransmit(trStr->hCard, &trStr->pioSendPci,
00358 trStr->pbSendBuffer, trStr->cbSendLength,
00359 &trStr->pioRecvPci, trStr->pbRecvBuffer,
00360 &trStr->pcbRecvLength);
00361 break;
00362
00363 case SCARD_CONTROL:
00364 ctStr = ((control_struct *) msgStruct->data);
00365 rv = MSGCheckHandleAssociation(ctStr->hCard, dwContextIndex);
00366 if (rv != 0) return rv;
00367 ctStr->rv = SCardControl(ctStr->hCard, ctStr->dwControlCode,
00368 ctStr->pbSendBuffer, ctStr->cbSendLength,
00369 ctStr->pbRecvBuffer, ctStr->cbRecvLength,
00370 &ctStr->dwBytesReturned);
00371 break;
00372
00373 case SCARD_GET_ATTRIB:
00374 gsStr = ((getset_struct *) msgStruct->data);
00375 rv = MSGCheckHandleAssociation(gsStr->hCard, dwContextIndex);
00376 if (rv != 0) return rv;
00377 gsStr->rv = SCardGetAttrib(gsStr->hCard, gsStr->dwAttrId,
00378 gsStr->pbAttr, &gsStr->cbAttrLen);
00379 break;
00380
00381 case SCARD_SET_ATTRIB:
00382 gsStr = ((getset_struct *) msgStruct->data);
00383 rv = MSGCheckHandleAssociation(gsStr->hCard, dwContextIndex);
00384 if (rv != 0) return rv;
00385 gsStr->rv = SCardSetAttrib(gsStr->hCard, gsStr->dwAttrId,
00386 gsStr->pbAttr, gsStr->cbAttrLen);
00387 break;
00388
00389 case SCARD_TRANSMIT_EXTENDED:
00390 {
00391 transmit_struct_extended *treStr;
00392 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
00393 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
00394
00395 treStr = ((transmit_struct_extended *) msgStruct->data);
00396 rv = MSGCheckHandleAssociation(treStr->hCard, dwContextIndex);
00397 if (rv != 0) return rv;
00398
00399
00400 if (treStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
00401 {
00402
00403 memcpy(pbSendBuffer, treStr->data,
00404 PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*treStr));
00405
00406
00407 rv = SHMMessageReceive(
00408 pbSendBuffer+PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*treStr),
00409 treStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
00410 psContext[dwContextIndex].dwClientID,
00411 PCSCLITE_SERVER_ATTEMPTS);
00412 if (rv)
00413 Log1(PCSC_LOG_CRITICAL, "reception failed");
00414 }
00415 else
00416 memcpy(pbSendBuffer, treStr->data, treStr->cbSendLength);
00417
00418 treStr->rv = SCardTransmit(treStr->hCard, &treStr->pioSendPci,
00419 pbSendBuffer, treStr->cbSendLength,
00420 &treStr->pioRecvPci, pbRecvBuffer,
00421 &treStr->pcbRecvLength);
00422
00423 treStr->size = sizeof(*treStr) + treStr->pcbRecvLength;
00424 if (treStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
00425 {
00426
00427 memcpy(treStr->data, pbRecvBuffer, PCSCLITE_MAX_MESSAGE_SIZE
00428 - sizeof(*treStr));
00429
00430 rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
00431 psContext[dwContextIndex].dwClientID,
00432 PCSCLITE_SERVER_ATTEMPTS);
00433 if (rv)
00434 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00435
00436 rv = SHMMessageSend(pbRecvBuffer + PCSCLITE_MAX_MESSAGE_SIZE
00437 - sizeof(*treStr),
00438 treStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
00439 psContext[dwContextIndex].dwClientID,
00440 PCSCLITE_SERVER_ATTEMPTS);
00441 if (rv)
00442 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00443 }
00444 else
00445 {
00446
00447 memcpy(treStr->data, pbRecvBuffer, treStr->pcbRecvLength);
00448
00449 rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
00450 psContext[dwContextIndex].dwClientID,
00451 PCSCLITE_SERVER_ATTEMPTS);
00452 if (rv)
00453 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00454 }
00455 }
00456 break;
00457
00458 case SCARD_CONTROL_EXTENDED:
00459 {
00460 control_struct_extended *cteStr;
00461 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
00462 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
00463
00464 cteStr = ((control_struct_extended *) msgStruct->data);
00465 rv = MSGCheckHandleAssociation(cteStr->hCard, dwContextIndex);
00466 if (rv != 0) return rv;
00467
00468
00469 if (cteStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
00470 {
00471
00472 memcpy(pbSendBuffer, cteStr->data,
00473 PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*cteStr));
00474
00475
00476 rv = SHMMessageReceive(
00477 pbSendBuffer+PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*cteStr),
00478 cteStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
00479 psContext[dwContextIndex].dwClientID,
00480 PCSCLITE_SERVER_ATTEMPTS);
00481 if (rv)
00482 Log1(PCSC_LOG_CRITICAL, "reception failed");
00483 }
00484 else
00485 memcpy(pbSendBuffer, cteStr->data, cteStr->cbSendLength);
00486
00487 cteStr->rv = SCardControl(cteStr->hCard, cteStr->dwControlCode,
00488 pbSendBuffer, cteStr->cbSendLength,
00489 pbRecvBuffer, cteStr->cbRecvLength,
00490 &cteStr->pdwBytesReturned);
00491
00492 cteStr->size = sizeof(*cteStr) + cteStr->pdwBytesReturned;
00493 if (cteStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
00494 {
00495
00496 memcpy(cteStr->data, pbRecvBuffer, PCSCLITE_MAX_MESSAGE_SIZE
00497 - sizeof(*cteStr));
00498
00499 rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
00500 psContext[dwContextIndex].dwClientID,
00501 PCSCLITE_SERVER_ATTEMPTS);
00502 if (rv)
00503 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00504
00505 rv = SHMMessageSend(pbRecvBuffer + PCSCLITE_MAX_MESSAGE_SIZE
00506 - sizeof(*cteStr),
00507 cteStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
00508 psContext[dwContextIndex].dwClientID,
00509 PCSCLITE_SERVER_ATTEMPTS);
00510 if (rv)
00511 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00512 }
00513 else
00514 {
00515
00516 memcpy(cteStr->data, pbRecvBuffer, cteStr->pdwBytesReturned);
00517
00518 rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
00519 psContext[dwContextIndex].dwClientID,
00520 PCSCLITE_SERVER_ATTEMPTS);
00521 if (rv)
00522 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00523 }
00524 }
00525 break;
00526
00527 default:
00528 Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", msgStruct->command);
00529 return -1;
00530 }
00531
00532 return 0;
00533 }
00534
00535 LONG MSGAddContext(SCARDCONTEXT hContext, DWORD dwContextIndex)
00536 {
00537 psContext[dwContextIndex].hContext = hContext;
00538 return SCARD_S_SUCCESS;
00539 }
00540
00541 LONG MSGRemoveContext(SCARDCONTEXT hContext, DWORD dwContextIndex)
00542 {
00543 int i;
00544 LONG rv;
00545
00546 if (psContext[dwContextIndex].hContext == hContext)
00547 {
00548 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
00549 {
00550
00551
00552
00553
00554 if (psContext[dwContextIndex].hCard[i] != 0)
00555 {
00556 PREADER_CONTEXT rContext = NULL;
00557 DWORD dwLockId;
00558
00559
00560
00561
00562 rv = RFReaderInfoById(psContext[dwContextIndex].hCard[i],
00563 &rContext);
00564 if (rv != SCARD_S_SUCCESS)
00565 return rv;
00566
00567 dwLockId = rContext->dwLockId;
00568 rContext->dwLockId = 0;
00569
00570 if (psContext[dwContextIndex].hCard[i] != dwLockId)
00571 {
00572
00573
00574
00575
00576 rv = SCARD_W_REMOVED_CARD;
00577 }
00578 else
00579 {
00580
00581
00582
00583
00584
00585 rv = SCardStatus(psContext[dwContextIndex].hCard[i], NULL,
00586 NULL, NULL, NULL, NULL, NULL);
00587 }
00588
00589 if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
00590 SCardDisconnect(psContext[dwContextIndex].hCard[i],
00591 SCARD_LEAVE_CARD);
00592 else
00593 SCardDisconnect(psContext[dwContextIndex].hCard[i],
00594 SCARD_RESET_CARD);
00595
00596 psContext[dwContextIndex].hCard[i] = 0;
00597 }
00598 }
00599
00600 psContext[dwContextIndex].hContext = 0;
00601 return SCARD_S_SUCCESS;
00602 }
00603
00604 return SCARD_E_INVALID_VALUE;
00605 }
00606
00607 LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard, DWORD dwContextIndex)
00608 {
00609 int i;
00610
00611 if (psContext[dwContextIndex].hContext == hContext)
00612 {
00613
00614
00615
00616
00617 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
00618 {
00619 if (psContext[dwContextIndex].hCard[i] == 0)
00620 {
00621 psContext[dwContextIndex].hCard[i] = hCard;
00622 break;
00623 }
00624 }
00625
00626 if (i == PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS)
00627 {
00628 return SCARD_F_INTERNAL_ERROR;
00629 } else
00630 {
00631 return SCARD_S_SUCCESS;
00632 }
00633
00634 }
00635
00636 return SCARD_E_INVALID_VALUE;
00637 }
00638
00639 LONG MSGRemoveHandle(SCARDHANDLE hCard, DWORD dwContextIndex)
00640 {
00641 int i;
00642
00643 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
00644 {
00645 if (psContext[dwContextIndex].hCard[i] == hCard)
00646 {
00647 psContext[dwContextIndex].hCard[i] = 0;
00648 return SCARD_S_SUCCESS;
00649 }
00650 }
00651
00652 return SCARD_E_INVALID_VALUE;
00653 }
00654
00655
00656 LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, DWORD dwContextIndex)
00657 {
00658 int i;
00659
00660 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
00661 {
00662 if (psContext[dwContextIndex].hCard[i] == hCard)
00663 {
00664 return 0;
00665 }
00666 }
00667
00668
00669 Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
00670 SYS_Sleep(2);
00671
00672 return -1;
00673 }
00674
00675 LONG MSGCleanupClient(DWORD dwContextIndex)
00676 {
00677 if (psContext[dwContextIndex].hContext != 0)
00678 {
00679 SCardReleaseContext(psContext[dwContextIndex].hContext);
00680 MSGRemoveContext(psContext[dwContextIndex].hContext, dwContextIndex);
00681 }
00682
00683 psContext[dwContextIndex].dwClientID = 0;
00684 psContext[dwContextIndex].protocol_major = 0;
00685 psContext[dwContextIndex].protocol_minor = 0;
00686
00687 return 0;
00688 }