b409c9b7be486b720fbbea6ed36a12c967148f4a
[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, CLONE_KERNEL);
338         if (SdoUdpInstance_g.m_ThreadHandle == 0) {
339                 Ret = kEplSdoUdpThreadError;
340                 goto Exit;
341         }
342
343       Exit:
344         return Ret;
345
346 }
347
348 //---------------------------------------------------------------------------
349 //
350 // Function:    EplSdoUdpuInitCon
351 //
352 // Description: init a new connect
353 //
354 //
355 //
356 // Parameters:  pSdoConHandle_p = pointer for the new connection handle
357 //              uiTargetNodeId_p = NodeId of the target node
358 //
359 //
360 // Returns:     tEplKernel  = Errorcode
361 //
362 //
363 // State:
364 //
365 //---------------------------------------------------------------------------
366 tEplKernel EplSdoUdpuInitCon(tEplSdoConHdl *pSdoConHandle_p,
367                              unsigned int uiTargetNodeId_p)
368 {
369         tEplKernel Ret;
370         unsigned int uiCount;
371         unsigned int uiFreeCon;
372         tEplSdoUdpCon *pSdoUdpCon;
373
374         Ret = kEplSuccessful;
375
376         // get free entry in control structure
377         uiCount = 0;
378         uiFreeCon = EPL_SDO_MAX_CONNECTION_UDP;
379         pSdoUdpCon = &SdoUdpInstance_g.m_aSdoAbsUdpConnection[0];
380         while (uiCount < EPL_SDO_MAX_CONNECTION_UDP) {
381                 if ((pSdoUdpCon->m_ulIpAddr & htonl(0xFF)) == htonl(uiTargetNodeId_p)) {        // existing connection to target node found
382                         // set handle
383                         *pSdoConHandle_p = (uiCount | EPL_SDO_UDP_HANDLE);
384
385                         goto Exit;
386                 } else if ((pSdoUdpCon->m_ulIpAddr == 0)
387                            && (pSdoUdpCon->m_uiPort == 0)) {
388                         uiFreeCon = uiCount;
389                 }
390                 uiCount++;
391                 pSdoUdpCon++;
392         }
393
394         if (uiFreeCon == EPL_SDO_MAX_CONNECTION_UDP) {
395                 // error no free handle
396                 Ret = kEplSdoUdpNoFreeHandle;
397         } else {
398                 pSdoUdpCon =
399                     &SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiFreeCon];
400                 // save infos for connection
401                 pSdoUdpCon->m_uiPort = htons(EPL_C_SDO_EPL_PORT);
402                 pSdoUdpCon->m_ulIpAddr = htonl(0xC0A86400 | uiTargetNodeId_p);  // 192.168.100.uiTargetNodeId_p
403
404                 // set handle
405                 *pSdoConHandle_p = (uiFreeCon | EPL_SDO_UDP_HANDLE);
406
407         }
408
409       Exit:
410         return Ret;
411
412 }
413
414 //---------------------------------------------------------------------------
415 //
416 // Function:    EplSdoUdpuSendData
417 //
418 // Description: send data using exisiting connection
419 //
420 //
421 //
422 // Parameters:  SdoConHandle_p  = connection handle
423 //              pSrcData_p      = pointer to data
424 //              dwDataSize_p    = number of databyte
425 //                                  -> without asend-header!!!
426 //
427 // Returns:     tEplKernel  = Errorcode
428 //
429 //
430 // State:
431 //
432 //---------------------------------------------------------------------------
433 tEplKernel EplSdoUdpuSendData(tEplSdoConHdl SdoConHandle_p,
434                               tEplFrame *pSrcData_p, u32 dwDataSize_p)
435 {
436         tEplKernel Ret;
437         int iError;
438         unsigned int uiArray;
439         struct sockaddr_in Addr;
440
441         Ret = kEplSuccessful;
442
443         uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
444         if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
445                 Ret = kEplSdoUdpInvalidHdl;
446                 goto Exit;
447         }
448         //set message type
449         AmiSetByteToLe(&pSrcData_p->m_le_bMessageType, 0x06);   // SDO
450         // target node id (for Udp = 0)
451         AmiSetByteToLe(&pSrcData_p->m_le_bDstNodeId, 0x00);
452         // set source-nodeid (for Udp = 0)
453         AmiSetByteToLe(&pSrcData_p->m_le_bSrcNodeId, 0x00);
454
455         // calc size
456         dwDataSize_p += EPL_ASND_HEADER_SIZE;
457
458         // call sendto
459         Addr.sin_family = AF_INET;
460         Addr.sin_port =
461             (unsigned short)SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].
462             m_uiPort;
463         Addr.sin_addr.s_addr =
464             SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr;
465
466         iError = sendto(SdoUdpInstance_g.m_UdpSocket,   // sockethandle
467                         (const char *)&pSrcData_p->m_le_bMessageType,   // data to send
468                         dwDataSize_p,   // number of bytes to send
469                         0,      // flags
470                         (struct sockaddr *)&Addr,       // target
471                         sizeof(struct sockaddr_in));    // sizeof targetadress
472         if (iError < 0) {
473                 EPL_DBGLVL_SDO_TRACE1
474                     ("EplSdoUdpuSendData: sendto() finished with %i\n", iError);
475                 Ret = kEplSdoUdpSendError;
476                 goto Exit;
477         }
478
479       Exit:
480         return Ret;
481
482 }
483
484 //---------------------------------------------------------------------------
485 //
486 // Function:    EplSdoUdpuDelCon
487 //
488 // Description: delete connection from intern structure
489 //
490 //
491 //
492 // Parameters:  SdoConHandle_p  = connection handle
493 //
494 // Returns:     tEplKernel  = Errorcode
495 //
496 //
497 // State:
498 //
499 //---------------------------------------------------------------------------
500 tEplKernel EplSdoUdpuDelCon(tEplSdoConHdl SdoConHandle_p)
501 {
502         tEplKernel Ret;
503         unsigned int uiArray;
504
505         uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
506
507         if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
508                 Ret = kEplSdoUdpInvalidHdl;
509                 goto Exit;
510         } else {
511                 Ret = kEplSuccessful;
512         }
513
514         // delete connection
515         SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr = 0;
516         SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_uiPort = 0;
517
518       Exit:
519         return Ret;
520 }
521
522 //=========================================================================//
523 //                                                                         //
524 //          P R I V A T E   F U N C T I O N S                              //
525 //                                                                         //
526 //=========================================================================//
527
528 //---------------------------------------------------------------------------
529 //
530 // Function:        EplSdoUdpThread
531 //
532 // Description:     thread check socket for new data
533 //
534 //
535 //
536 // Parameters:      lpParameter = pointer to parameter type tEplSdoUdpThreadPara
537 //
538 //
539 // Returns:         u32   =   errorcode
540 //
541 //
542 // State:
543 //
544 //---------------------------------------------------------------------------
545 static int EplSdoUdpThread(void *pArg_p)
546 {
547
548         tEplSdoUdpInstance *pInstance;
549         struct sockaddr_in RemoteAddr;
550         int iError;
551         int iCount;
552         int iFreeEntry;
553         u8 abBuffer[EPL_MAX_SDO_REC_FRAME_SIZE];
554         unsigned int uiSize;
555         tEplSdoConHdl SdoConHdl;
556
557         pInstance = (tEplSdoUdpInstance *) pArg_p;
558         daemonize("EplSdoUdpThread");
559         allow_signal(SIGTERM);
560
561         for (; pInstance->m_iTerminateThread == 0;)
562
563         {
564                 // wait for data
565                 uiSize = sizeof(struct sockaddr);
566                 iError = recvfrom(pInstance->m_UdpSocket,       // Socket
567                                   (char *)&abBuffer[0], // buffer for data
568                                   sizeof(abBuffer),     // size of the buffer
569                                   0,    // flags
570                                   (struct sockaddr *)&RemoteAddr,
571                                   (int *)&uiSize);
572                 if (iError == -ERESTARTSYS) {
573                         break;
574                 }
575                 if (iError > 0) {
576                         // get handle for higher layer
577                         iCount = 0;
578                         iFreeEntry = 0xFFFF;
579                         while (iCount < EPL_SDO_MAX_CONNECTION_UDP) {
580                                 // check if this connection is already known
581                                 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
582                                      m_ulIpAddr == RemoteAddr.sin_addr.s_addr)
583                                     && (pInstance->
584                                         m_aSdoAbsUdpConnection[iCount].
585                                         m_uiPort == RemoteAddr.sin_port)) {
586                                         break;
587                                 }
588
589                                 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
590                                      m_ulIpAddr == 0)
591                                     && (pInstance->
592                                         m_aSdoAbsUdpConnection[iCount].
593                                         m_uiPort == 0)
594                                     && (iFreeEntry == 0xFFFF))
595                                 {
596                                         iFreeEntry = iCount;
597                                 }
598
599                                 iCount++;
600                         }
601
602                         if (iCount == EPL_SDO_MAX_CONNECTION_UDP) {
603                                 // connection unknown
604                                 // see if there is a free handle
605                                 if (iFreeEntry != 0xFFFF) {
606                                         // save adress infos
607                                         pInstance->
608                                             m_aSdoAbsUdpConnection[iFreeEntry].
609                                             m_ulIpAddr =
610                                             RemoteAddr.sin_addr.s_addr;
611                                         pInstance->
612                                             m_aSdoAbsUdpConnection[iFreeEntry].
613                                             m_uiPort = RemoteAddr.sin_port;
614                                         // call callback
615                                         SdoConHdl = iFreeEntry;
616                                         SdoConHdl |= EPL_SDO_UDP_HANDLE;
617                                         // offset 4 -> start of SDO Sequence header
618                                         pInstance->m_fpSdoAsySeqCb(SdoConHdl,
619                                                                    (tEplAsySdoSeq
620                                                                     *) &
621                                                                    abBuffer[4],
622                                                                    (iError -
623                                                                     4));
624                                 } else {
625                                         EPL_DBGLVL_SDO_TRACE0
626                                             ("Error in EplSdoUdpThread() no free handle\n");
627                                 }
628
629                         } else {
630                                 // known connection
631                                 // call callback with correct handle
632                                 SdoConHdl = iCount;
633                                 SdoConHdl |= EPL_SDO_UDP_HANDLE;
634                                 // offset 4 -> start of SDO Sequence header
635                                 pInstance->m_fpSdoAsySeqCb(SdoConHdl,
636                                                            (tEplAsySdoSeq *) &
637                                                            abBuffer[4],
638                                                            (iError - 4));
639                         }
640                 }               // end of  if(iError!=SOCKET_ERROR)
641         }                       // end of for(;;)
642
643         complete_and_exit(&SdoUdpInstance_g.m_CompletionUdpThread, 0);
644         return 0;
645 }
646
647 #endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
648
649 // EOF