Fix the race between capifs remount and node creation
[linux-2.6] / drivers / staging / epl / EplNmtCnu.c
1 /****************************************************************************
2
3   (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4       www.systec-electronic.com
5
6   Project:      openPOWERLINK
7
8   Description:  source file for NMT-CN-Userspace-Module
9
10   License:
11
12     Redistribution and use in source and binary forms, with or without
13     modification, are permitted provided that the following conditions
14     are met:
15
16     1. Redistributions of source code must retain the above copyright
17        notice, this list of conditions and the following disclaimer.
18
19     2. Redistributions in binary form must reproduce the above copyright
20        notice, this list of conditions and the following disclaimer in the
21        documentation and/or other materials provided with the distribution.
22
23     3. Neither the name of SYSTEC electronic GmbH nor the names of its
24        contributors may be used to endorse or promote products derived
25        from this software without prior written permission. For written
26        permission, please contact info@systec-electronic.com.
27
28     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32     COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
36     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39     POSSIBILITY OF SUCH DAMAGE.
40
41     Severability Clause:
42
43         If a provision of this License is or becomes illegal, invalid or
44         unenforceable in any jurisdiction, that shall not affect:
45         1. the validity or enforceability in that jurisdiction of any other
46            provision of this License; or
47         2. the validity or enforceability in other jurisdictions of that or
48            any other provision of this License.
49
50   -------------------------------------------------------------------------
51
52                 $RCSfile: EplNmtCnu.c,v $
53
54                 $Author: D.Krueger $
55
56                 $Revision: 1.6 $  $Date: 2008/10/17 15:32:32 $
57
58                 $State: Exp $
59
60                 Build Environment:
61                     GCC V3.4
62
63   -------------------------------------------------------------------------
64
65   Revision History:
66
67   2006/06/09 k.t.:   start of the implementation
68
69 ****************************************************************************/
70
71 #include "EplInc.h"
72 #include "user/EplNmtCnu.h"
73 #include "user/EplDlluCal.h"
74
75 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_CN)) != 0)
76
77 /***************************************************************************/
78 /*                                                                         */
79 /*                                                                         */
80 /*          G L O B A L   D E F I N I T I O N S                            */
81 /*                                                                         */
82 /*                                                                         */
83 /***************************************************************************/
84
85 //---------------------------------------------------------------------------
86 // const defines
87 //---------------------------------------------------------------------------
88
89 //---------------------------------------------------------------------------
90 // local types
91 //---------------------------------------------------------------------------
92
93 typedef struct {
94         unsigned int m_uiNodeId;
95         tEplNmtuCheckEventCallback m_pfnCheckEventCb;
96
97 } tEplNmtCnuInstance;
98
99 //---------------------------------------------------------------------------
100 // modul globale vars
101 //---------------------------------------------------------------------------
102
103 static tEplNmtCnuInstance EplNmtCnuInstance_g;
104
105 //---------------------------------------------------------------------------
106 // local function prototypes
107 //---------------------------------------------------------------------------
108
109 static tEplNmtCommand EplNmtCnuGetNmtCommand(tEplFrameInfo * pFrameInfo_p);
110
111 static BOOL EplNmtCnuNodeIdList(u8 * pbNmtCommandDate_p);
112
113 static tEplKernel EplNmtCnuCommandCb(tEplFrameInfo *pFrameInfo_p);
114
115 //=========================================================================//
116 //                                                                         //
117 //          P U B L I C   F U N C T I O N S                                //
118 //                                                                         //
119 //=========================================================================//
120
121 //---------------------------------------------------------------------------
122 //
123 // Function:    EplNmtCnuInit
124 //
125 // Description: init the first instance of the module
126 //
127 //
128 //
129 // Parameters:      uiNodeId_p = NodeId of the local node
130 //
131 //
132 // Returns:         tEplKernel = errorcode
133 //
134 //
135 // State:
136 //
137 //---------------------------------------------------------------------------
138 tEplKernel EplNmtCnuInit(unsigned int uiNodeId_p)
139 {
140         tEplKernel Ret;
141
142         Ret = EplNmtCnuAddInstance(uiNodeId_p);
143
144         return Ret;
145 }
146
147 //---------------------------------------------------------------------------
148 //
149 // Function:    EplNmtCnuAddInstance
150 //
151 // Description: init the add new instance of the module
152 //
153 //
154 //
155 // Parameters:      uiNodeId_p = NodeId of the local node
156 //
157 //
158 // Returns:         tEplKernel = errorcode
159 //
160 //
161 // State:
162 //
163 //---------------------------------------------------------------------------
164 tEplKernel EplNmtCnuAddInstance(unsigned int uiNodeId_p)
165 {
166         tEplKernel Ret;
167
168         Ret = kEplSuccessful;
169
170         // reset instance structure
171         EPL_MEMSET(&EplNmtCnuInstance_g, 0, sizeof(EplNmtCnuInstance_g));
172
173         // save nodeid
174         EplNmtCnuInstance_g.m_uiNodeId = uiNodeId_p;
175
176         // register callback-function for NMT-commands
177 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLU)) != 0)
178         Ret = EplDlluCalRegAsndService(kEplDllAsndNmtCommand,
179                                        EplNmtCnuCommandCb,
180                                        kEplDllAsndFilterLocal);
181 #endif
182
183         return Ret;
184
185 }
186
187 //---------------------------------------------------------------------------
188 //
189 // Function:    EplNmtCnuDelInstance
190 //
191 // Description: delte instance of the module
192 //
193 //
194 //
195 // Parameters:
196 //
197 //
198 // Returns:         tEplKernel = errorcode
199 //
200 //
201 // State:
202 //
203 //---------------------------------------------------------------------------
204 tEplKernel EplNmtCnuDelInstance(void)
205 {
206         tEplKernel Ret;
207
208         Ret = kEplSuccessful;
209
210 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLU)) != 0)
211         // deregister callback function from DLL
212         Ret = EplDlluCalRegAsndService(kEplDllAsndNmtCommand,
213                                        NULL, kEplDllAsndFilterNone);
214 #endif
215
216         return Ret;
217 }
218
219 //---------------------------------------------------------------------------
220 //
221 // Function:    EplNmtCnuSendNmtRequest
222 //
223 // Description: Send an NMT-Request to the MN
224 //
225 //
226 //
227 // Parameters:      uiNodeId_p = NodeId of the local node
228 //                  NmtCommand_p = requested NMT-Command
229 //
230 //
231 // Returns:         tEplKernel = errorcode
232 //
233 //
234 // State:
235 //
236 //---------------------------------------------------------------------------
237 tEplKernel EplNmtCnuSendNmtRequest(unsigned int uiNodeId_p,
238                                    tEplNmtCommand NmtCommand_p)
239 {
240         tEplKernel Ret;
241         tEplFrameInfo NmtRequestFrameInfo;
242         tEplFrame NmtRequestFrame;
243
244         Ret = kEplSuccessful;
245
246         // build frame
247         EPL_MEMSET(&NmtRequestFrame.m_be_abDstMac[0], 0x00, sizeof(NmtRequestFrame.m_be_abDstMac));     // set by DLL
248         EPL_MEMSET(&NmtRequestFrame.m_be_abSrcMac[0], 0x00, sizeof(NmtRequestFrame.m_be_abSrcMac));     // set by DLL
249         AmiSetWordToBe(&NmtRequestFrame.m_be_wEtherType,
250                        EPL_C_DLL_ETHERTYPE_EPL);
251         AmiSetByteToLe(&NmtRequestFrame.m_le_bDstNodeId, (u8) EPL_C_ADR_MN_DEF_NODE_ID);        // node id of the MN
252         AmiSetByteToLe(&NmtRequestFrame.m_le_bMessageType,
253                        (u8) kEplMsgTypeAsnd);
254         AmiSetByteToLe(&NmtRequestFrame.m_Data.m_Asnd.m_le_bServiceId,
255                        (u8) kEplDllAsndNmtRequest);
256         AmiSetByteToLe(&NmtRequestFrame.m_Data.m_Asnd.m_Payload.
257                        m_NmtRequestService.m_le_bNmtCommandId,
258                        (u8) NmtCommand_p);
259         AmiSetByteToLe(&NmtRequestFrame.m_Data.m_Asnd.m_Payload.m_NmtRequestService.m_le_bTargetNodeId, (u8) uiNodeId_p);       // target for the nmt command
260         EPL_MEMSET(&NmtRequestFrame.m_Data.m_Asnd.m_Payload.m_NmtRequestService.
261                    m_le_abNmtCommandData[0], 0x00,
262                    sizeof(NmtRequestFrame.m_Data.m_Asnd.m_Payload.
263                           m_NmtRequestService.m_le_abNmtCommandData));
264
265         // build info-structure
266         NmtRequestFrameInfo.m_NetTime.m_dwNanoSec = 0;
267         NmtRequestFrameInfo.m_NetTime.m_dwSec = 0;
268         NmtRequestFrameInfo.m_pFrame = &NmtRequestFrame;
269         NmtRequestFrameInfo.m_uiFrameSize = EPL_C_DLL_MINSIZE_NMTREQ;   // sizeof(NmtRequestFrame);
270
271         // send NMT-Request
272 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLU)) != 0)
273         Ret = EplDlluCalAsyncSend(&NmtRequestFrameInfo, // pointer to frameinfo
274                                   kEplDllAsyncReqPrioNmt);      // priority
275 #endif
276
277         return Ret;
278 }
279
280 //---------------------------------------------------------------------------
281 //
282 // Function:    EplNmtCnuRegisterStateChangeCb
283 //
284 // Description: register Callback-function go get informed about a
285 //              NMT-Change-State-Event
286 //
287 //
288 //
289 // Parameters:  pfnEplNmtStateChangeCb_p = functionpointer
290 //
291 //
292 // Returns:     tEplKernel  = errorcode
293 //
294 //
295 // State:
296 //
297 //---------------------------------------------------------------------------
298
299 tEplKernel EplNmtCnuRegisterCheckEventCb(tEplNmtuCheckEventCallback pfnEplNmtCheckEventCb_p)
300 {
301         tEplKernel Ret;
302
303         Ret = kEplSuccessful;
304
305         // save callback-function in modul global var
306         EplNmtCnuInstance_g.m_pfnCheckEventCb = pfnEplNmtCheckEventCb_p;
307
308         return Ret;
309
310 }
311
312 //=========================================================================//
313 //                                                                         //
314 //          P R I V A T E   F U N C T I O N S                              //
315 //                                                                         //
316 //=========================================================================//
317
318 //---------------------------------------------------------------------------
319 //
320 // Function:    EplNmtCnuCommandCb
321 //
322 // Description: callback funktion for NMT-Commands
323 //
324 //
325 //
326 // Parameters:      pFrameInfo_p = Frame with the NMT-Commando
327 //
328 //
329 // Returns:         tEplKernel = errorcode
330 //
331 //
332 // State:
333 //
334 //---------------------------------------------------------------------------
335 static tEplKernel EplNmtCnuCommandCb(tEplFrameInfo *pFrameInfo_p)
336 {
337         tEplKernel Ret = kEplSuccessful;
338         tEplNmtCommand NmtCommand;
339         BOOL fNodeIdInList;
340         tEplNmtEvent NmtEvent = kEplNmtEventNoEvent;
341
342         if (pFrameInfo_p == NULL) {
343                 Ret = kEplNmtInvalidFramePointer;
344                 goto Exit;
345         }
346
347         NmtCommand = EplNmtCnuGetNmtCommand(pFrameInfo_p);
348
349         // check NMT-Command
350         switch (NmtCommand) {
351
352                 //------------------------------------------------------------------------
353                 // plain NMT state commands
354         case kEplNmtCmdStartNode:
355                 {               // send NMT-Event to state maschine kEplNmtEventStartNode
356                         NmtEvent = kEplNmtEventStartNode;
357                         break;
358                 }
359
360         case kEplNmtCmdStopNode:
361                 {               // send NMT-Event to state maschine kEplNmtEventStopNode
362                         NmtEvent = kEplNmtEventStopNode;
363                         break;
364                 }
365
366         case kEplNmtCmdEnterPreOperational2:
367                 {               // send NMT-Event to state maschine kEplNmtEventEnterPreOperational2
368                         NmtEvent = kEplNmtEventEnterPreOperational2;
369                         break;
370                 }
371
372         case kEplNmtCmdEnableReadyToOperate:
373                 {               // send NMT-Event to state maschine kEplNmtEventEnableReadyToOperate
374                         NmtEvent = kEplNmtEventEnableReadyToOperate;
375                         break;
376                 }
377
378         case kEplNmtCmdResetNode:
379                 {               // send NMT-Event to state maschine kEplNmtEventResetNode
380                         NmtEvent = kEplNmtEventResetNode;
381                         break;
382                 }
383
384         case kEplNmtCmdResetCommunication:
385                 {               // send NMT-Event to state maschine kEplNmtEventResetCom
386                         NmtEvent = kEplNmtEventResetCom;
387                         break;
388                 }
389
390         case kEplNmtCmdResetConfiguration:
391                 {               // send NMT-Event to state maschine kEplNmtEventResetConfig
392                         NmtEvent = kEplNmtEventResetConfig;
393                         break;
394                 }
395
396         case kEplNmtCmdSwReset:
397                 {               // send NMT-Event to state maschine kEplNmtEventSwReset
398                         NmtEvent = kEplNmtEventSwReset;
399                         break;
400                 }
401
402                 //------------------------------------------------------------------------
403                 // extended NMT state commands
404
405         case kEplNmtCmdStartNodeEx:
406                 {
407                         // check if own nodeid is in EPL node list
408                         fNodeIdInList =
409                             EplNmtCnuNodeIdList(&
410                                                 (pFrameInfo_p->m_pFrame->m_Data.
411                                                  m_Asnd.m_Payload.
412                                                  m_NmtCommandService.
413                                                  m_le_abNmtCommandData[0]));
414                         if (fNodeIdInList != FALSE) {   // own nodeid in list
415                                 // send event to process command
416                                 NmtEvent = kEplNmtEventStartNode;
417                         }
418                         break;
419                 }
420
421         case kEplNmtCmdStopNodeEx:
422                 {               // check if own nodeid is in EPL node list
423                         fNodeIdInList =
424                             EplNmtCnuNodeIdList(&pFrameInfo_p->m_pFrame->m_Data.
425                                                 m_Asnd.m_Payload.
426                                                 m_NmtCommandService.
427                                                 m_le_abNmtCommandData[0]);
428                         if (fNodeIdInList != FALSE) {   // own nodeid in list
429                                 // send event to process command
430                                 NmtEvent = kEplNmtEventStopNode;
431                         }
432                         break;
433                 }
434
435         case kEplNmtCmdEnterPreOperational2Ex:
436                 {               // check if own nodeid is in EPL node list
437                         fNodeIdInList =
438                             EplNmtCnuNodeIdList(&pFrameInfo_p->m_pFrame->m_Data.
439                                                 m_Asnd.m_Payload.
440                                                 m_NmtCommandService.
441                                                 m_le_abNmtCommandData[0]);
442                         if (fNodeIdInList != FALSE) {   // own nodeid in list
443                                 // send event to process command
444                                 NmtEvent = kEplNmtEventEnterPreOperational2;
445                         }
446                         break;
447                 }
448
449         case kEplNmtCmdEnableReadyToOperateEx:
450                 {               // check if own nodeid is in EPL node list
451                         fNodeIdInList =
452                             EplNmtCnuNodeIdList(&pFrameInfo_p->m_pFrame->m_Data.
453                                                 m_Asnd.m_Payload.
454                                                 m_NmtCommandService.
455                                                 m_le_abNmtCommandData[0]);
456                         if (fNodeIdInList != FALSE) {   // own nodeid in list
457                                 // send event to process command
458                                 NmtEvent = kEplNmtEventEnableReadyToOperate;
459                         }
460                         break;
461                 }
462
463         case kEplNmtCmdResetNodeEx:
464                 {               // check if own nodeid is in EPL node list
465                         fNodeIdInList =
466                             EplNmtCnuNodeIdList(&pFrameInfo_p->m_pFrame->m_Data.
467                                                 m_Asnd.m_Payload.
468                                                 m_NmtCommandService.
469                                                 m_le_abNmtCommandData[0]);
470                         if (fNodeIdInList != FALSE) {   // own nodeid in list
471                                 // send event to process command
472                                 NmtEvent = kEplNmtEventResetNode;
473                         }
474                         break;
475                 }
476
477         case kEplNmtCmdResetCommunicationEx:
478                 {               // check if own nodeid is in EPL node list
479                         fNodeIdInList =
480                             EplNmtCnuNodeIdList(&pFrameInfo_p->m_pFrame->m_Data.
481                                                 m_Asnd.m_Payload.
482                                                 m_NmtCommandService.
483                                                 m_le_abNmtCommandData[0]);
484                         if (fNodeIdInList != FALSE) {   // own nodeid in list
485                                 // send event to process command
486                                 NmtEvent = kEplNmtEventResetCom;
487                         }
488                         break;
489                 }
490
491         case kEplNmtCmdResetConfigurationEx:
492                 {               // check if own nodeid is in EPL node list
493                         fNodeIdInList =
494                             EplNmtCnuNodeIdList(&pFrameInfo_p->m_pFrame->m_Data.
495                                                 m_Asnd.m_Payload.
496                                                 m_NmtCommandService.
497                                                 m_le_abNmtCommandData[0]);
498                         if (fNodeIdInList != FALSE) {   // own nodeid in list
499                                 // send event to process command
500                                 NmtEvent = kEplNmtEventResetConfig;
501                         }
502                         break;
503                 }
504
505         case kEplNmtCmdSwResetEx:
506                 {               // check if own nodeid is in EPL node list
507                         fNodeIdInList =
508                             EplNmtCnuNodeIdList(&pFrameInfo_p->m_pFrame->m_Data.
509                                                 m_Asnd.m_Payload.
510                                                 m_NmtCommandService.
511                                                 m_le_abNmtCommandData[0]);
512                         if (fNodeIdInList != FALSE) {   // own nodeid in list
513                                 // send event to process command
514                                 NmtEvent = kEplNmtEventSwReset;
515                         }
516                         break;
517                 }
518
519                 //------------------------------------------------------------------------
520                 // NMT managing commands
521
522                 // TODO: add functions to process managing command (optional)
523
524         case kEplNmtCmdNetHostNameSet:
525                 {
526                         break;
527                 }
528
529         case kEplNmtCmdFlushArpEntry:
530                 {
531                         break;
532                 }
533
534                 //------------------------------------------------------------------------
535                 // NMT info services
536
537                 // TODO: forward event with infos to the application (optional)
538
539         case kEplNmtCmdPublishConfiguredCN:
540                 {
541                         break;
542                 }
543
544         case kEplNmtCmdPublishActiveCN:
545                 {
546                         break;
547                 }
548
549         case kEplNmtCmdPublishPreOperational1:
550                 {
551                         break;
552                 }
553
554         case kEplNmtCmdPublishPreOperational2:
555                 {
556                         break;
557                 }
558
559         case kEplNmtCmdPublishReadyToOperate:
560                 {
561                         break;
562                 }
563
564         case kEplNmtCmdPublishOperational:
565                 {
566                         break;
567                 }
568
569         case kEplNmtCmdPublishStopped:
570                 {
571                         break;
572                 }
573
574         case kEplNmtCmdPublishEmergencyNew:
575                 {
576                         break;
577                 }
578
579         case kEplNmtCmdPublishTime:
580                 {
581                         break;
582                 }
583
584                 //-----------------------------------------------------------------------
585                 // error from MN
586                 // -> requested command not supported by MN
587         case kEplNmtCmdInvalidService:
588                 {
589
590                         // TODO: errorevent to application
591                         break;
592                 }
593
594                 //------------------------------------------------------------------------
595                 // default
596         default:
597                 {
598                         Ret = kEplNmtUnknownCommand;
599                         goto Exit;
600                 }
601
602         }                       // end of switch(NmtCommand)
603
604         if (NmtEvent != kEplNmtEventNoEvent) {
605                 if (EplNmtCnuInstance_g.m_pfnCheckEventCb != NULL) {
606                         Ret = EplNmtCnuInstance_g.m_pfnCheckEventCb(NmtEvent);
607                         if (Ret == kEplReject) {
608                                 Ret = kEplSuccessful;
609                                 goto Exit;
610                         } else if (Ret != kEplSuccessful) {
611                                 goto Exit;
612                         }
613                 }
614 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMTU)) != 0)
615                 Ret = EplNmtuNmtEvent(NmtEvent);
616 #endif
617         }
618
619       Exit:
620         return Ret;
621
622 }
623
624 //---------------------------------------------------------------------------
625 //
626 // Function:    EplNmtCnuGetNmtCommand()
627 //
628 // Description: returns the NMT-Command from the frame
629 //
630 //
631 //
632 // Parameters:      pFrameInfo_p = pointer to the Frame
633 //                                 with the NMT-Command
634 //
635 //
636 // Returns:         tEplNmtCommand = NMT-Command
637 //
638 //
639 // State:
640 //
641 //---------------------------------------------------------------------------
642 static tEplNmtCommand EplNmtCnuGetNmtCommand(tEplFrameInfo * pFrameInfo_p)
643 {
644         tEplNmtCommand NmtCommand;
645         tEplNmtCommandService *pNmtCommandService;
646
647         pNmtCommandService =
648             &pFrameInfo_p->m_pFrame->m_Data.m_Asnd.m_Payload.
649             m_NmtCommandService;
650
651         NmtCommand =
652             (tEplNmtCommand) AmiGetByteFromLe(&pNmtCommandService->
653                                               m_le_bNmtCommandId);
654
655         return NmtCommand;
656 }
657
658 //---------------------------------------------------------------------------
659 //
660 // Function:    EplNmtCnuNodeIdList()
661 //
662 // Description: check if the own nodeid is set in EPL Node List
663 //
664 //
665 //
666 // Parameters:      pbNmtCommandDate_p = pointer to the data of the NMT Command
667 //
668 //
669 // Returns:         BOOL = TRUE if nodeid is set in EPL Node List
670 //                         FALSE if nodeid not set in EPL Node List
671 //
672 //
673 // State:
674 //
675 //---------------------------------------------------------------------------
676 static BOOL EplNmtCnuNodeIdList(u8 * pbNmtCommandDate_p)
677 {
678         BOOL fNodeIdInList;
679         unsigned int uiByteOffset;
680         u8 bBitOffset;
681         u8 bNodeListByte;
682
683         // get byte-offset of the own nodeid in NodeIdList
684         // devide though 8
685         uiByteOffset = (unsigned int)(EplNmtCnuInstance_g.m_uiNodeId >> 3);
686         // get bitoffset
687         bBitOffset = (u8) EplNmtCnuInstance_g.m_uiNodeId % 8;
688
689         bNodeListByte = AmiGetByteFromLe(&pbNmtCommandDate_p[uiByteOffset]);
690         if ((bNodeListByte & bBitOffset) == 0) {
691                 fNodeIdInList = FALSE;
692         } else {
693                 fNodeIdInList = TRUE;
694         }
695
696         return fNodeIdInList;
697 }
698
699 #endif // #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_CN)) != 0)
700
701 // EOF