Staging: epl: do not use CLONE_SIGHAND with allow_signal()
[safe/jmp/linux-2.6] / drivers / staging / epl / EplSdoUdpu.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 SDO/UDP-Protocolabstractionlayer 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: EplSdoUdpu.c,v $
53
54                 $Author: D.Krueger $
55
56                 $Revision: 1.8 $  $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/26 k.t.:   start of the implementation
68
69 ****************************************************************************/
70
71 #include "user/EplSdoUdpu.h"
72
73 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
74
75 #include "SocketLinuxKernel.h"
76 #include <linux/completion.h>
77 #include <linux/sched.h>
78
79 /***************************************************************************/
80 /*                                                                         */
81 /*                                                                         */
82 /*          G L O B A L   D E F I N I T I O N S                            */
83 /*                                                                         */
84 /*                                                                         */
85 /***************************************************************************/
86
87 //---------------------------------------------------------------------------
88 // const defines
89 //---------------------------------------------------------------------------
90
91 #ifndef EPL_SDO_MAX_CONNECTION_UDP
92 #define EPL_SDO_MAX_CONNECTION_UDP  5
93 #endif
94
95 //---------------------------------------------------------------------------
96 // local types
97 //---------------------------------------------------------------------------
98
99 typedef struct {
100         unsigned long m_ulIpAddr;       // in network byte order
101         unsigned int m_uiPort;  // in network byte order
102
103 } tEplSdoUdpCon;
104
105 // instance table
106 typedef struct {
107         tEplSdoUdpCon m_aSdoAbsUdpConnection[EPL_SDO_MAX_CONNECTION_UDP];
108         tEplSequLayerReceiveCb m_fpSdoAsySeqCb;
109         SOCKET m_UdpSocket;
110
111         struct completion m_CompletionUdpThread;
112         int m_ThreadHandle;
113         int m_iTerminateThread;
114 } tEplSdoUdpInstance;
115
116 //---------------------------------------------------------------------------
117 // modul globale vars
118 //---------------------------------------------------------------------------
119
120 static tEplSdoUdpInstance SdoUdpInstance_g;
121
122 //---------------------------------------------------------------------------
123 // local function prototypes
124 //---------------------------------------------------------------------------
125
126 static int EplSdoUdpThread(void *pArg_p);
127
128 /***************************************************************************/
129 /*                                                                         */
130 /*                                                                         */
131 /*          C L A S S  <EPL-SDO-UDP-Layer>                                 */
132 /*                                                                         */
133 /*                                                                         */
134 /***************************************************************************/
135 //
136 // Description: Protocolabstraction layer for UDP
137 //
138 //
139 /***************************************************************************/
140
141 //=========================================================================//
142 //                                                                         //
143 //          P U B L I C   F U N C T I O N S                                //
144 //                                                                         //
145 //=========================================================================//
146
147 //---------------------------------------------------------------------------
148 //
149 // Function:    EplSdoUdpuInit
150 //
151 // Description: init first instance of the module
152 //
153 //
154 //
155 // Parameters:  pReceiveCb_p    =   functionpointer to Sdo-Sequence layer
156 //                                  callback-function
157 //
158 //
159 // Returns:     tEplKernel  = Errorcode
160 //
161 //
162 // State:
163 //
164 //---------------------------------------------------------------------------
165 tEplKernel EplSdoUdpuInit(tEplSequLayerReceiveCb fpReceiveCb_p)
166 {
167         tEplKernel Ret;
168
169         Ret = EplSdoUdpuAddInstance(fpReceiveCb_p);
170
171         return Ret;
172 }
173
174 //---------------------------------------------------------------------------
175 //
176 // Function:    EplSdoUdpuAddInstance
177 //
178 // Description: init additional instance of the module
179 //              înit socket and start Listen-Thread
180 //
181 //
182 //
183 // Parameters:  pReceiveCb_p    =   functionpointer to Sdo-Sequence layer
184 //                                  callback-function
185 //
186 //
187 // Returns:     tEplKernel  = Errorcode
188 //
189 //
190 // State:
191 //
192 //---------------------------------------------------------------------------
193 tEplKernel EplSdoUdpuAddInstance(tEplSequLayerReceiveCb fpReceiveCb_p)
194 {
195         tEplKernel Ret;
196
197         // set instance variables to 0
198         EPL_MEMSET(&SdoUdpInstance_g, 0x00, sizeof(SdoUdpInstance_g));
199
200         Ret = kEplSuccessful;
201
202         // save pointer to callback-function
203         if (fpReceiveCb_p != NULL) {
204                 SdoUdpInstance_g.m_fpSdoAsySeqCb = fpReceiveCb_p;
205         } else {
206                 Ret = kEplSdoUdpMissCb;
207                 goto Exit;
208         }
209
210         init_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
211         SdoUdpInstance_g.m_iTerminateThread = 0;
212         SdoUdpInstance_g.m_ThreadHandle = 0;
213         SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
214
215         Ret = EplSdoUdpuConfig(INADDR_ANY, 0);
216
217       Exit:
218         return Ret;
219 }
220
221 //---------------------------------------------------------------------------
222 //
223 // Function:    EplSdoUdpuDelInstance
224 //
225 // Description: del instance of the module
226 //              del socket and del Listen-Thread
227 //
228 //
229 //
230 // Parameters:
231 //
232 //
233 // Returns:     tEplKernel  = Errorcode
234 //
235 //
236 // State:
237 //
238 //---------------------------------------------------------------------------
239 tEplKernel EplSdoUdpuDelInstance(void)
240 {
241         tEplKernel Ret;
242
243         Ret = kEplSuccessful;
244
245         if (SdoUdpInstance_g.m_ThreadHandle != 0) {     // listen thread was started
246                 // close thread
247                 SdoUdpInstance_g.m_iTerminateThread = 1;
248                 /* kill_proc(SdoUdpInstance_g.m_ThreadHandle, SIGTERM, 1 ); */
249                 send_sig(SIGTERM, SdoUdpInstance_g.m_ThreadHandle, 1);
250                 wait_for_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
251                 SdoUdpInstance_g.m_ThreadHandle = 0;
252         }
253
254         if (SdoUdpInstance_g.m_UdpSocket != INVALID_SOCKET) {
255                 // close socket
256                 closesocket(SdoUdpInstance_g.m_UdpSocket);
257                 SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
258         }
259         return Ret;
260 }
261
262 //---------------------------------------------------------------------------
263 //
264 // Function:    EplSdoUdpuConfig
265 //
266 // Description: reconfigurate socket with new IP-Address
267 //              -> needed for NMT ResetConfiguration
268 //
269 // Parameters:  ulIpAddr_p      = IpAddress in platform byte order
270 //              uiPort_p        = port number in platform byte order
271 //
272 //
273 // Returns:     tEplKernel  = Errorcode
274 //
275 //
276 // State:
277 //
278 //---------------------------------------------------------------------------
279 tEplKernel EplSdoUdpuConfig(unsigned long ulIpAddr_p, unsigned int uiPort_p)
280 {
281         tEplKernel Ret;
282         struct sockaddr_in Addr;
283         int iError;
284
285         Ret = kEplSuccessful;
286
287         if (uiPort_p == 0) {    // set UDP port to default port number
288                 uiPort_p = EPL_C_SDO_EPL_PORT;
289         } else if (uiPort_p > 65535) {
290                 Ret = kEplSdoUdpSocketError;
291                 goto Exit;
292         }
293
294         if (SdoUdpInstance_g.m_ThreadHandle != 0) {     // listen thread was started
295
296                 // close old thread
297                 SdoUdpInstance_g.m_iTerminateThread = 1;
298                 /* kill_proc(SdoUdpInstance_g.m_ThreadHandle, SIGTERM, 1 ); */
299                 send_sig(SIGTERM, SdoUdpInstance_g.m_ThreadHandle, 1);
300                 wait_for_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
301                 SdoUdpInstance_g.m_iTerminateThread = 0;
302                 SdoUdpInstance_g.m_ThreadHandle = 0;
303         }
304
305         if (SdoUdpInstance_g.m_UdpSocket != INVALID_SOCKET) {
306                 // close socket
307                 iError = closesocket(SdoUdpInstance_g.m_UdpSocket);
308                 SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
309                 if (iError != 0) {
310                         Ret = kEplSdoUdpSocketError;
311                         goto Exit;
312                 }
313         }
314         // create Socket
315         SdoUdpInstance_g.m_UdpSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
316         if (SdoUdpInstance_g.m_UdpSocket == INVALID_SOCKET) {
317                 Ret = kEplSdoUdpNoSocket;
318                 EPL_DBGLVL_SDO_TRACE0("EplSdoUdpuConfig: socket() failed\n");
319                 goto Exit;
320         }
321         // bind socket
322         Addr.sin_family = AF_INET;
323         Addr.sin_port = htons((unsigned short)uiPort_p);
324         Addr.sin_addr.s_addr = htonl(ulIpAddr_p);
325         iError =
326             bind(SdoUdpInstance_g.m_UdpSocket, (struct sockaddr *)&Addr,
327                  sizeof(Addr));
328         if (iError < 0) {
329                 //iError = WSAGetLastError();
330                 EPL_DBGLVL_SDO_TRACE1
331                     ("EplSdoUdpuConfig: bind() finished with %i\n", iError);
332                 Ret = kEplSdoUdpNoSocket;
333                 goto Exit;
334         }
335         // create Listen-Thread
336         SdoUdpInstance_g.m_ThreadHandle =
337                 kernel_thread(EplSdoUdpThread, &SdoUdpInstance_g,
338                                 CLONE_FS | CLONE_FILES);
339         if (SdoUdpInstance_g.m_ThreadHandle == 0) {
340                 Ret = kEplSdoUdpThreadError;
341                 goto Exit;
342         }
343
344       Exit:
345         return Ret;
346
347 }
348
349 //---------------------------------------------------------------------------
350 //
351 // Function:    EplSdoUdpuInitCon
352 //
353 // Description: init a new connect
354 //
355 //
356 //
357 // Parameters:  pSdoConHandle_p = pointer for the new connection handle
358 //              uiTargetNodeId_p = NodeId of the target node
359 //
360 //
361 // Returns:     tEplKernel  = Errorcode
362 //
363 //
364 // State:
365 //
366 //---------------------------------------------------------------------------
367 tEplKernel EplSdoUdpuInitCon(tEplSdoConHdl *pSdoConHandle_p,
368                              unsigned int uiTargetNodeId_p)
369 {
370         tEplKernel Ret;
371         unsigned int uiCount;
372         unsigned int uiFreeCon;
373         tEplSdoUdpCon *pSdoUdpCon;
374
375         Ret = kEplSuccessful;
376
377         // get free entry in control structure
378         uiCount = 0;
379         uiFreeCon = EPL_SDO_MAX_CONNECTION_UDP;
380         pSdoUdpCon = &SdoUdpInstance_g.m_aSdoAbsUdpConnection[0];
381         while (uiCount < EPL_SDO_MAX_CONNECTION_UDP) {
382                 if ((pSdoUdpCon->m_ulIpAddr & htonl(0xFF)) == htonl(uiTargetNodeId_p)) {        // existing connection to target node found
383                         // set handle
384                         *pSdoConHandle_p = (uiCount | EPL_SDO_UDP_HANDLE);
385
386                         goto Exit;
387                 } else if ((pSdoUdpCon->m_ulIpAddr == 0)
388                            && (pSdoUdpCon->m_uiPort == 0)) {
389                         uiFreeCon = uiCount;
390                 }
391                 uiCount++;
392                 pSdoUdpCon++;
393         }
394
395         if (uiFreeCon == EPL_SDO_MAX_CONNECTION_UDP) {
396                 // error no free handle
397                 Ret = kEplSdoUdpNoFreeHandle;
398         } else {
399                 pSdoUdpCon =
400                     &SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiFreeCon];
401                 // save infos for connection
402                 pSdoUdpCon->m_uiPort = htons(EPL_C_SDO_EPL_PORT);
403                 pSdoUdpCon->m_ulIpAddr = htonl(0xC0A86400 | uiTargetNodeId_p);  // 192.168.100.uiTargetNodeId_p
404
405                 // set handle
406                 *pSdoConHandle_p = (uiFreeCon | EPL_SDO_UDP_HANDLE);
407
408         }
409
410       Exit:
411         return Ret;
412
413 }
414
415 //---------------------------------------------------------------------------
416 //
417 // Function:    EplSdoUdpuSendData
418 //
419 // Description: send data using exisiting connection
420 //
421 //
422 //
423 // Parameters:  SdoConHandle_p  = connection handle
424 //              pSrcData_p      = pointer to data
425 //              dwDataSize_p    = number of databyte
426 //                                  -> without asend-header!!!
427 //
428 // Returns:     tEplKernel  = Errorcode
429 //
430 //
431 // State:
432 //
433 //---------------------------------------------------------------------------
434 tEplKernel EplSdoUdpuSendData(tEplSdoConHdl SdoConHandle_p,
435                               tEplFrame *pSrcData_p, u32 dwDataSize_p)
436 {
437         tEplKernel Ret;
438         int iError;
439         unsigned int uiArray;
440         struct sockaddr_in Addr;
441
442         Ret = kEplSuccessful;
443
444         uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
445         if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
446                 Ret = kEplSdoUdpInvalidHdl;
447                 goto Exit;
448         }
449         //set message type
450         AmiSetByteToLe(&pSrcData_p->m_le_bMessageType, 0x06);   // SDO
451         // target node id (for Udp = 0)
452         AmiSetByteToLe(&pSrcData_p->m_le_bDstNodeId, 0x00);
453         // set source-nodeid (for Udp = 0)
454         AmiSetByteToLe(&pSrcData_p->m_le_bSrcNodeId, 0x00);
455
456         // calc size
457         dwDataSize_p += EPL_ASND_HEADER_SIZE;
458
459         // call sendto
460         Addr.sin_family = AF_INET;
461         Addr.sin_port =
462             (unsigned short)SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].
463             m_uiPort;
464         Addr.sin_addr.s_addr =
465             SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr;
466
467         iError = sendto(SdoUdpInstance_g.m_UdpSocket,   // sockethandle
468                         (const char *)&pSrcData_p->m_le_bMessageType,   // data to send
469                         dwDataSize_p,   // number of bytes to send
470                         0,      // flags
471                         (struct sockaddr *)&Addr,       // target
472                         sizeof(struct sockaddr_in));    // sizeof targetadress
473         if (iError < 0) {
474                 EPL_DBGLVL_SDO_TRACE1
475                     ("EplSdoUdpuSendData: sendto() finished with %i\n", iError);
476                 Ret = kEplSdoUdpSendError;
477                 goto Exit;
478         }
479
480       Exit:
481         return Ret;
482
483 }
484
485 //---------------------------------------------------------------------------
486 //
487 // Function:    EplSdoUdpuDelCon
488 //
489 // Description: delete connection from intern structure
490 //
491 //
492 //
493 // Parameters:  SdoConHandle_p  = connection handle
494 //
495 // Returns:     tEplKernel  = Errorcode
496 //
497 //
498 // State:
499 //
500 //---------------------------------------------------------------------------
501 tEplKernel EplSdoUdpuDelCon(tEplSdoConHdl SdoConHandle_p)
502 {
503         tEplKernel Ret;
504         unsigned int uiArray;
505
506         uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
507
508         if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
509                 Ret = kEplSdoUdpInvalidHdl;
510                 goto Exit;
511         } else {
512                 Ret = kEplSuccessful;
513         }
514
515         // delete connection
516         SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr = 0;
517         SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_uiPort = 0;
518
519       Exit:
520         return Ret;
521 }
522
523 //=========================================================================//
524 //                                                                         //
525 //          P R I V A T E   F U N C T I O N S                              //
526 //                                                                         //
527 //=========================================================================//
528
529 //---------------------------------------------------------------------------
530 //
531 // Function:        EplSdoUdpThread
532 //
533 // Description:     thread check socket for new data
534 //
535 //
536 //
537 // Parameters:      lpParameter = pointer to parameter type tEplSdoUdpThreadPara
538 //
539 //
540 // Returns:         u32   =   errorcode
541 //
542 //
543 // State:
544 //
545 //---------------------------------------------------------------------------
546 static int EplSdoUdpThread(void *pArg_p)
547 {
548
549         tEplSdoUdpInstance *pInstance;
550         struct sockaddr_in RemoteAddr;
551         int iError;
552         int iCount;
553         int iFreeEntry;
554         u8 abBuffer[EPL_MAX_SDO_REC_FRAME_SIZE];
555         unsigned int uiSize;
556         tEplSdoConHdl SdoConHdl;
557
558         pInstance = (tEplSdoUdpInstance *) pArg_p;
559         daemonize("EplSdoUdpThread");
560         allow_signal(SIGTERM);
561
562         for (; pInstance->m_iTerminateThread == 0;)
563
564         {
565                 // wait for data
566                 uiSize = sizeof(struct sockaddr);
567                 iError = recvfrom(pInstance->m_UdpSocket,       // Socket
568                                   (char *)&abBuffer[0], // buffer for data
569                                   sizeof(abBuffer),     // size of the buffer
570                                   0,    // flags
571                                   (struct sockaddr *)&RemoteAddr,
572                                   (int *)&uiSize);
573                 if (iError == -ERESTARTSYS) {
574                         break;
575                 }
576                 if (iError > 0) {
577                         // get handle for higher layer
578                         iCount = 0;
579                         iFreeEntry = 0xFFFF;
580                         while (iCount < EPL_SDO_MAX_CONNECTION_UDP) {
581                                 // check if this connection is already known
582                                 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
583                                      m_ulIpAddr == RemoteAddr.sin_addr.s_addr)
584                                     && (pInstance->
585                                         m_aSdoAbsUdpConnection[iCount].
586                                         m_uiPort == RemoteAddr.sin_port)) {
587                                         break;
588                                 }
589
590                                 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
591                                      m_ulIpAddr == 0)
592                                     && (pInstance->
593                                         m_aSdoAbsUdpConnection[iCount].
594                                         m_uiPort == 0)
595                                     && (iFreeEntry == 0xFFFF))
596                                 {
597                                         iFreeEntry = iCount;
598                                 }
599
600                                 iCount++;
601                         }
602
603                         if (iCount == EPL_SDO_MAX_CONNECTION_UDP) {
604                                 // connection unknown
605                                 // see if there is a free handle
606                                 if (iFreeEntry != 0xFFFF) {
607                                         // save adress infos
608                                         pInstance->
609                                             m_aSdoAbsUdpConnection[iFreeEntry].
610                                             m_ulIpAddr =
611                                             RemoteAddr.sin_addr.s_addr;
612                                         pInstance->
613                                             m_aSdoAbsUdpConnection[iFreeEntry].
614                                             m_uiPort = RemoteAddr.sin_port;
615                                         // call callback
616                                         SdoConHdl = iFreeEntry;
617                                         SdoConHdl |= EPL_SDO_UDP_HANDLE;
618                                         // offset 4 -> start of SDO Sequence header
619                                         pInstance->m_fpSdoAsySeqCb(SdoConHdl,
620                                                                    (tEplAsySdoSeq
621                                                                     *) &
622                                                                    abBuffer[4],
623                                                                    (iError -
624                                                                     4));
625                                 } else {
626                                         EPL_DBGLVL_SDO_TRACE0
627                                             ("Error in EplSdoUdpThread() no free handle\n");
628                                 }
629
630                         } else {
631                                 // known connection
632                                 // call callback with correct handle
633                                 SdoConHdl = iCount;
634                                 SdoConHdl |= EPL_SDO_UDP_HANDLE;
635                                 // offset 4 -> start of SDO Sequence header
636                                 pInstance->m_fpSdoAsySeqCb(SdoConHdl,
637                                                            (tEplAsySdoSeq *) &
638                                                            abBuffer[4],
639                                                            (iError - 4));
640                         }
641                 }               // end of  if(iError!=SOCKET_ERROR)
642         }                       // end of for(;;)
643
644         complete_and_exit(&SdoUdpInstance_g.m_CompletionUdpThread, 0);
645         return 0;
646 }
647
648 #endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
649
650 // EOF