upstream Makefile doesn't have an install target
[debian/uapevent] / uapevent.c
1 /** @file  uapevent.c
2  *
3  *  @brief Program to receive events from the driver/firmware of the uAP
4  *         driver.
5  * 
6  * Copyright (C) 2008-2009, Marvell International Ltd. 
7  *
8  * This software file (the "File") is distributed by Marvell International 
9  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
10  * (the "License").  You may use, redistribute and/or modify this File in 
11  * accordance with the terms and conditions of the License, a copy of which 
12  * is available along with the File in the gpl.txt file or by writing to 
13  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
14  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
15  *
16  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
17  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
18  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
19  * this warranty disclaimer.
20  *
21  */
22 /****************************************************************************
23 Change log:
24     03/18/08: Initial creation
25 ****************************************************************************/
26
27 /****************************************************************************
28         Header files
29 ****************************************************************************/
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <signal.h>
36 #include <time.h>
37 #include <sys/time.h>
38 #include <getopt.h>
39
40 #include <sys/socket.h>
41 #include <linux/netlink.h>
42 #include "uapevent.h"
43
44 /****************************************************************************
45         Definitions
46 ****************************************************************************/
47 /** Enable or disable debug outputs */
48 #define DEBUG   0
49
50 /****************************************************************************
51         Global variables
52 ****************************************************************************/
53 /** Termination flag */
54 int terminate_flag = 0;
55
56 /****************************************************************************
57         Local functions
58 ****************************************************************************/
59 /** 
60  *  @brief Signal handler
61  *
62  *  @param sig      Received signal number
63  *  @return         N/A
64  */
65 void
66 sig_handler(int sig)
67 {
68     printf("Stopping application.\n");
69 #if DEBUG
70     printf("Process ID of process killed = %d\n", getpid());
71 #endif
72     terminate_flag = 1;
73 }
74
75 /** 
76  *  @brief Dump hex data
77  *
78  *  @param p        A pointer to data buffer
79  *  @param len      The len of data buffer
80  *  @param delim    Deliminator character
81  *  @return         Hex integer
82  */
83 static void
84 hexdump(void *p, s32 len, s8 delim)
85 {
86     s32 i;
87     u8 *s = p;
88     for (i = 0; i < len; i++) {
89         if (i != len - 1)
90             printf("%02x%c", *s++, delim);
91         else
92             printf("%02x\n", *s);
93         if ((i + 1) % 16 == 0)
94             printf("\n");
95     }
96 }
97
98 /** 
99  *  @brief Prints a MAC address in colon separated form from raw data
100  *
101  *  @param raw      A pointer to the hex data buffer
102  *  @return         N/A
103  */
104 void
105 print_mac(u8 * raw)
106 {
107     printf("%02x:%02x:%02x:%02x:%02x:%02x", (unsigned int) raw[0],
108            (unsigned int) raw[1], (unsigned int) raw[2], (unsigned int) raw[3],
109            (unsigned int) raw[4], (unsigned int) raw[5]);
110     return;
111 }
112
113 /** 
114  *  @brief Print usage information
115  *
116  *  @return         N/A
117  */
118 void
119 print_usage(void)
120 {
121     printf("\n");
122     printf("Usage : uapevent.exe [-v] [-h]\n");
123     printf("    -v               : Print version information\n");
124     printf("    -h               : Print help information\n");
125     printf("\n");
126 }
127
128 /** 
129  *  @brief Parse and print STA deauthentication event data
130  *
131  *  @param buffer   Pointer to received event buffer
132  *  @param size     Length of the received event data
133  *  @return         N/A
134  */
135 void
136 print_event_sta_deauth(u8 * buffer, u16 size)
137 {
138     EVENTBUF_STA_DEAUTH *event_body = NULL;
139
140     if (size < sizeof(EVENTBUF_STA_DEAUTH)) {
141         printf("ERR:Event buffer too small!\n");
142         return;
143     }
144     event_body = (EVENTBUF_STA_DEAUTH *) buffer;
145     event_body->ReasonCode = uap_le16_to_cpu(event_body->ReasonCode);
146     printf("EVENT: STA_DEAUTH\n");
147     printf("Deauthenticated STA MAC: ");
148     print_mac(event_body->StaMacAddress);
149     printf("\nReason: ");
150     switch (event_body->ReasonCode) {
151     case 1:
152         printf("Unspecified reason.\n");
153         break;
154     case 2:
155         printf("Previous authentication no longer valid.\n");
156         break;
157     case 3:
158         printf("Deauthenticated because sending STA is leaving IBSS or ESS.\n");
159         break;
160     case 4:
161         printf("Disassociated due to inactivity.\n");
162         break;
163     case 5:
164         printf
165             ("Disassociated because AP is unable to handle all currently associated STAs.\n");
166         break;
167     case 6:
168         printf("Class 2 frame received from nonauthenticated STA.\n");
169         break;
170     case 7:
171         printf("Class 3 frame received from nonassociated STA.\n");
172         break;
173     case 8:
174         printf("Disassociated because sending STA is leaving BSS.\n");
175         break;
176     case 9:
177         printf
178             ("STA requesting (re)association is not authenticated with responding STA.\n");
179         break;
180     case 10:
181         printf
182             ("Disassociated because the information in the Power Capability element is unacceptable.\n");
183         break;
184     case 11:
185         printf
186             ("Disassociated because the information in the Supported Channels element is unacceptable.\n");
187         break;
188     case 13:
189         printf("Invalid information element.\n");
190         break;
191     case 14:
192         printf("Message integrity code (MIC) failure.\n");
193         break;
194     case 15:
195         printf("4-Way Handshake timeout.\n");
196         break;
197     case 16:
198         printf("Group Key Handshake timeout.\n");
199         break;
200     case 17:
201         printf("Information element in 4-Way Handshake different from\n");
202         printf("   (Re)Association Request/Probe Response/Beacon frame.\n");
203         break;
204     case 18:
205         printf("Invalid group cipher.\n");
206         break;
207     case 19:
208         printf("Invalid pairwise cipher.\n");
209         break;
210     case 20:
211         printf("Invalid AKMP.\n");
212         break;
213     case 21:
214         printf("Unsupported RSN information element version.\n");
215         break;
216     case 22:
217         printf("Invalid RSN information element capabilities.\n");
218         break;
219     case 23:
220         printf("IEEE 802.1X authentication failed.\n");
221         break;
222     case 24:
223         printf("Cipher suite rejected because of the security policy.\n");
224         break;
225     case 32:
226         printf("Disassociated for unspecified, QoS-related reason.\n");
227         break;
228     case 33:
229         printf
230             ("Disassociated because QoS AP lacks sufficient bandwidth for this QoS STA.\n");
231         break;
232     case 34:
233         printf
234             ("Disassociated because excessive number of frames need to be acknowledged\n");
235         printf
236             (" but are not acknowledged due to AP transmissions and or poor channel conditions.\n");
237         break;
238     case 35:
239         printf
240             ("Disassociated because STA is transmitting outside the limits of its TXOPs.\n");
241         break;
242     case 36:
243         printf
244             ("Requested from peer STA as the STA is leaving the BSS or resetting.\n");
245         break;
246     case 37:
247         printf
248             ("Requested from peer STA as it does not want to use the mechanism.\n");
249         break;
250     case 38:
251         printf("Requested from peer STA as the STA received frames using");
252         printf("   the mechanism for which a setup is required.\n");
253         break;
254     case 39:
255         printf("Requested from peer STA due to timeout.\n");
256         break;
257     case 45:
258         printf("Peer STA does not support the requested cipher suite.\n");
259         break;
260     default:
261         printf("Reserved or Unspecified\n");
262         break;
263     }
264     return;
265 }
266
267 /** 
268  *  @brief Prints mgmt frame
269  *
270  *  @param mgmt_tlv A pointer to mgmt_tlv
271  *  @param tlv_len  Length of tlv payload
272  *  @return         N/A
273  */
274 void
275 print_mgmt_frame(MrvlIETypes_MgmtFrameSet_t * mgmt_tlv, int tlv_len)
276 {
277     IEEEtypes_AssocRqst_t *assoc_req = NULL;
278     IEEEtypes_ReAssocRqst_t *reassoc_req = NULL;
279     IEEEtypes_AssocRsp_t *assoc_resp = NULL;
280     u16 frmctl = 0;
281     printf("\nMgmt Frame:\n");
282     memcpy(&frmctl, &mgmt_tlv->FrameControl, sizeof(u16));
283     printf("FrameControl: 0x%x\n", frmctl);
284     if (mgmt_tlv->FrameControl.Type != 0) {
285         printf("Frame type=%d subtype=%d:\n", mgmt_tlv->FrameControl.Type,
286                mgmt_tlv->FrameControl.Subtype);
287         hexdump(mgmt_tlv->FrameContents, tlv_len - sizeof(u16), ' ');
288         return;
289     }
290     switch (mgmt_tlv->FrameControl.Subtype) {
291     case SUBTYPE_ASSOC_REQUEST:
292         printf("Assoc Request:\n");
293         assoc_req = (IEEEtypes_AssocRqst_t *) mgmt_tlv->FrameContents;
294         printf("CapInfo: 0x%x  ListenInterval: 0x%x \n",
295                uap_le16_to_cpu(assoc_req->CapInfo),
296                uap_le16_to_cpu(assoc_req->ListenInterval));
297         printf("AssocReqIE:\n");
298         hexdump(assoc_req->IEBuffer,
299                 tlv_len - sizeof(IEEEtypes_AssocRqst_t) -
300                 sizeof(IEEEtypes_FrameCtl_t), ' ');
301         break;
302     case SUBTYPE_REASSOC_REQUEST:
303         printf("ReAssoc Request:\n");
304         reassoc_req = (IEEEtypes_ReAssocRqst_t *) mgmt_tlv->FrameContents;
305         printf("CapInfo: 0x%x  ListenInterval: 0x%x \n",
306                uap_le16_to_cpu(reassoc_req->CapInfo),
307                uap_le16_to_cpu(reassoc_req->ListenInterval));
308         printf("Current AP address: ");
309         print_mac(reassoc_req->CurrentApAddr);
310         printf("\nReAssocReqIE:\n");
311         hexdump(reassoc_req->IEBuffer,
312                 tlv_len - sizeof(IEEEtypes_ReAssocRqst_t) -
313                 sizeof(IEEEtypes_FrameCtl_t), ' ');
314         break;
315     case SUBTYPE_ASSOC_RESPONSE:
316     case SUBTYPE_REASSOC_RESPONSE:
317         if (mgmt_tlv->FrameControl.Subtype == SUBTYPE_ASSOC_RESPONSE)
318             printf("Assoc Response:\n");
319         else
320             printf("ReAssoc Response:\n");
321         assoc_resp = (IEEEtypes_AssocRsp_t *) mgmt_tlv->FrameContents;
322         printf("CapInfo: 0x%x  StatusCode: %d  AID: 0x%x \n",
323                uap_le16_to_cpu(assoc_resp->CapInfo),
324                (int) (uap_le16_to_cpu(assoc_resp->StatusCode)),
325                uap_le16_to_cpu(assoc_resp->AId) & 0x3fff);
326         break;
327     default:
328         printf("Frame subtype = %d:\n", mgmt_tlv->FrameControl.Subtype);
329         hexdump(mgmt_tlv->FrameContents, tlv_len - sizeof(u16), ' ');
330         break;
331     }
332     return;
333 }
334
335 /** 
336  *  @brief Parse and print STA associate event data
337  *
338  *  @param buffer   Pointer to received buffer
339  *  @param size     Length of the received event data
340  *  @return         N/A
341  */
342 void
343 print_event_sta_assoc(u8 * buffer, u16 size)
344 {
345     int tlvBufLeft = size;
346     u16 tlvType, tlvLen;
347     tlvbuf_header *tlv = NULL;
348     MrvlIEtypes_WapiInfoSet_t *wapi_tlv = NULL;
349     MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = NULL;
350     EVENTBUF_STA_ASSOC *event_body = NULL;
351     if (size < sizeof(EVENTBUF_STA_ASSOC)) {
352         printf("ERR:Event buffer too small!\n");
353         return;
354     }
355     event_body = (EVENTBUF_STA_ASSOC *) buffer;
356     printf("EVENT: STA_ASSOCIATE\n");
357     printf("Associated STA MAC: ");
358     print_mac(event_body->StaMacAddress);
359     printf("\n");
360     tlvBufLeft = size - sizeof(EVENTBUF_STA_ASSOC);
361     if (tlvBufLeft < (int) sizeof(tlvbuf_header))
362         return;
363     tlv = (tlvbuf_header *) (buffer + sizeof(EVENTBUF_STA_ASSOC));
364
365     while (tlvBufLeft >= (int) sizeof(tlvbuf_header)) {
366         tlvType = uap_le16_to_cpu(tlv->type);
367         tlvLen = uap_le16_to_cpu(tlv->len);
368         if ((sizeof(tlvbuf_header) + tlvLen) > tlvBufLeft) {
369             printf("wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlvLen, tlvBufLeft);
370             break;
371         }
372         switch (tlvType) {
373         case MRVL_WAPI_INFO_TLV_ID:
374             wapi_tlv = (MrvlIEtypes_WapiInfoSet_t *) tlv;
375             printf("WAPI Multicast PN:\n");
376             hexdump(wapi_tlv->MulticastPN, tlvLen, ' ');
377             break;
378         case MRVL_MGMT_FRAME_TLV_ID:
379             mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *) tlv;
380             print_mgmt_frame(mgmt_tlv, tlvLen);
381             break;
382         default:
383             printf("unknown tlv: %d\n", tlvType);
384             break;
385         }
386         tlvBufLeft -= (sizeof(tlvbuf_header) + tlvLen);
387         tlv = (tlvbuf_header *) ((u8 *) tlv + tlvLen + sizeof(tlvbuf_header));
388     }
389     return;
390 }
391
392 /** 
393  *  @brief Parse and print BSS start event data
394  *
395  *  @param buffer   Pointer to received buffer
396  *  @param size     Length of the received event data
397  *  @return         N/A
398  */
399 void
400 print_event_bss_start(u8 * buffer, u16 size)
401 {
402     EVENTBUF_BSS_START *event_body = NULL;
403
404     if (size < sizeof(EVENTBUF_BSS_START)) {
405         printf("ERR:Event buffer too small!\n");
406         return;
407     }
408     event_body = (EVENTBUF_BSS_START *) buffer;
409     printf("EVENT: BSS_START ");
410     printf("BSS MAC: ");
411     print_mac(event_body->apMacAddress);
412     printf("\n");
413     return;
414 }
415
416 /** 
417  *  @brief Prints station reject state
418  *
419  *  @param state      fail state
420  *  @return         N/A
421  */
422 void
423 print_reject_state(u8 state)
424 {
425     switch (state) {
426     case REJECT_STATE_FAIL_EAPOL_2:
427         printf("Reject state: FAIL_EAPOL_2\n");
428         break;
429     case REJECT_STATE_FAIL_EAPOL_4:
430         printf("Reject state: FAIL_EAPOL_4:\n");
431         break;
432     case REJECT_STATE_FAIL_EAPOL_GROUP_2:
433         printf("Reject state: FAIL_EAPOL_GROUP_2\n");
434         break;
435     default:
436         printf("ERR: unknown reject state %d\n", state);
437         break;
438     }
439     return;
440 }
441
442 /** 
443  *  @brief Prints station reject reason
444  *
445  *  @param reason      reason code
446  *  @return         N/A
447  */
448 void
449 print_reject_reason(u16 reason)
450 {
451     switch (reason) {
452     case IEEEtypes_REASON_INVALID_IE:
453         printf("Reject reason: Invalid IE\n");
454         break;
455     case IEEEtypes_REASON_MIC_FAILURE:
456         printf("Reject reason: Mic Failure\n");
457         break;
458     default:
459         printf("Reject reason: %d\n", reason);
460         break;
461     }
462     return;
463 }
464
465 /** 
466  *  @brief Prints EAPOL state
467  *
468  *  @param state    eapol state
469  *  @return         N/A
470  */
471 void
472 print_eapol_state(u8 state)
473 {
474     switch (state) {
475     case EAPOL_START:
476         printf("Eapol state: EAPOL_START\n");
477         break;
478     case EAPOL_WAIT_PWK2:
479         printf("Eapol state: EAPOL_WAIT_PWK2\n");
480         break;
481     case EAPOL_WAIT_PWK4:
482         printf("Eapol state: EAPOL_WAIT_PWK4\n");
483         break;
484     case EAPOL_WAIT_GTK2:
485         printf("Eapol state: EAPOL_WAIT_GTK2\n");
486         break;
487     case EAPOL_END:
488         printf("Eapol state: EAPOL_END\n");
489         break;
490     default:
491         printf("ERR: unknow eapol state%d\n", state);
492         break;
493     }
494     return;
495 }
496
497 /** 
498  *  @brief Parse and print debug event data
499  *
500  *  @param buffer   Pointer to received buffer
501  *  @param size     Length of the received event data
502  *  @return         N/A
503  */
504 void
505 print_event_debug(u8 * buffer, u16 size)
506 {
507     EVENTBUF_DEBUG *event_body = NULL;
508     if (size < sizeof(EVENTBUF_DEBUG)) {
509         printf("ERR:Event buffer too small!\n");
510         return;
511     }
512     event_body = (EVENTBUF_DEBUG *) buffer;
513     printf("Debug Event Type: %s\n",
514            (event_body->debugtype == 0) ? "EVENT" : "INFO");
515     printf("%s log:\n",
516            (uap_le32_to_cpu(event_body->debugIdMajor) ==
517             DEBUG_ID_MAJ_AUTHENTICATOR) ? "Authenticator" : "Assoc_agent");
518     if (uap_le32_to_cpu(event_body->debugIdMajor) == DEBUG_ID_MAJ_AUTHENTICATOR) {
519         switch (uap_le32_to_cpu(event_body->debugIdMinor)) {
520         case DEBUG_MAJ_AUTH_MIN_PWK1:
521             printf("EAPOL Key message 1 (PWK):\n");
522             hexdump((u8 *) & event_body->info.eapol_pwkMsg,
523                     sizeof(EAPOL_KeyMsg_Debug_t), ' ');
524             break;
525         case DEBUG_MAJ_AUTH_MIN_PWK2:
526             printf("EAPOL Key message 2 (PWK):\n");
527             hexdump((u8 *) & event_body->info.eapol_pwkMsg,
528                     sizeof(EAPOL_KeyMsg_Debug_t), ' ');
529             break;
530         case DEBUG_MAJ_AUTH_MIN_PWK3:
531             printf("EAPOL Key message 3 (PWK):\n");
532             hexdump((u8 *) & event_body->info.eapol_pwkMsg,
533                     sizeof(EAPOL_KeyMsg_Debug_t), ' ');
534             break;
535         case DEBUG_MAJ_AUTH_MIN_PWK4:
536             printf("EAPOL Key message 4: (PWK)\n");
537             hexdump((u8 *) & event_body->info.eapol_pwkMsg,
538                     sizeof(EAPOL_KeyMsg_Debug_t), ' ');
539             break;
540         case DEBUG_MAJ_AUTH_MIN_GWK1:
541             printf("EAPOL Key message 1: (GWK)\n");
542             hexdump((u8 *) & event_body->info.eapol_pwkMsg,
543                     sizeof(EAPOL_KeyMsg_Debug_t), ' ');
544             break;
545         case DEBUG_MAJ_AUTH_MIN_GWK2:
546             printf("EAPOL Key message 2: (GWK)\n");
547             hexdump((u8 *) & event_body->info.eapol_pwkMsg,
548                     sizeof(EAPOL_KeyMsg_Debug_t), ' ');
549             break;
550         case DEBUG_MAJ_AUTH_MIN_STA_REJ:
551             printf("Reject STA MAC: ");
552             print_mac(event_body->info.sta_reject.staMacAddr);
553             printf("\n");
554             print_reject_state(event_body->info.sta_reject.reject_state);
555             print_reject_reason(uap_le16_to_cpu
556                                 (event_body->info.sta_reject.reject_reason));
557             break;
558         case DEBUG_MAJ_AUTH_MIN_EAPOL_TR:
559             printf("STA MAC: ");
560             print_mac(event_body->info.eapol_state.staMacAddr);
561             printf("\n");
562             print_eapol_state(event_body->info.eapol_state.eapolState);
563             break;
564         default:
565             printf("ERR: unknow debugIdMinor: %d\n",
566                    (int) uap_le32_to_cpu(event_body->debugIdMinor));
567             hexdump(buffer, size, ' ');
568             return;
569         }
570     } else if (uap_le32_to_cpu(event_body->debugIdMajor) ==
571                DEBUG_ID_MAJ_ASSOC_AGENT) {
572         switch (uap_le32_to_cpu(event_body->debugIdMinor)) {
573         case DEBUG_ID_MAJ_ASSOC_MIN_WPA_IE:
574             printf("STA MAC: ");
575             print_mac(event_body->info.wpaIe.staMacAddr);
576             printf("\n");
577             printf("wpa ie:\n");
578             hexdump(event_body->info.wpaIe.wpa_ie, MAX_WPA_IE_LEN, ' ');
579             break;
580         case DEBUG_ID_MAJ_ASSOC_MIN_STA_REJ:
581             printf("Reject STA MAC: ");
582             print_mac(event_body->info.sta_reject.staMacAddr);
583             printf("\n");
584             print_reject_state(event_body->info.sta_reject.reject_state);
585             print_reject_reason(uap_le16_to_cpu
586                                 (event_body->info.sta_reject.reject_reason));
587             break;
588         default:
589             printf("ERR: unknow debugIdMinor: %d\n",
590                    (int) uap_le32_to_cpu(event_body->debugIdMinor));
591             hexdump(buffer, size, ' ');
592             return;
593         }
594     }
595     return;
596 }
597
598 /** 
599  *  @brief Parse and print received event information
600  *
601  *  @param event    Pointer to received event
602  *  @param size     Length of the received event
603  *  @return         N/A
604  */
605 void
606 print_event(EVENTHEADER * event, u16 size)
607 {
608     u32 event_id = event->EventId & EVENT_ID_MASK;
609     switch (event_id) {
610     case MICRO_AP_EV_ID_STA_DEAUTH:
611         print_event_sta_deauth(event->EventData, size - EVENT_ID_LEN);
612         break;
613     case MICRO_AP_EV_ID_STA_ASSOC:
614         print_event_sta_assoc(event->EventData, size - EVENT_ID_LEN);
615         break;
616     case MICRO_AP_EV_ID_BSS_START:
617         print_event_bss_start(event->EventData, size - EVENT_ID_LEN);
618         break;
619     case MICRO_AP_EV_ID_DEBUG:
620         print_event_debug(event->EventData, size - EVENT_ID_LEN);
621         break;
622     case MICRO_AP_EV_BSS_IDLE:
623         printf("EVENT: BSS_IDLE\n");
624         break;
625     case MICRO_AP_EV_BSS_ACTIVE:
626         printf("EVENT: BSS_ACTIVE\n");
627         break;
628     default:
629         printf("ERR:Undefined event type (%X). Dumping event buffer:\n",
630                (unsigned int) event_id);
631         hexdump((void *) event, size, ' ');
632         break;
633     }
634     return;
635 }
636
637 /** 
638  *  @brief Read event data from netlink socket
639  *
640  *  @param sk_fd    Netlink socket handler
641  *  @param buffer   Pointer to the data buffer
642  *  @param nlh      Pointer to netlink message header
643  *  @param msg      Pointer to message header
644  *  @return         Number of bytes read or UAP_FAILURE
645  */
646 int
647 read_event_netlink_socket(int sk_fd, unsigned char *buffer,
648                           struct nlmsghdr *nlh, struct msghdr *msg)
649 {
650     int count = -1;
651     count = recvmsg(sk_fd, msg, 0);
652 #if DEBUG
653     printf("DBG:Waiting for message from NETLINK.\n");
654 #endif
655     if (count < 0) {
656         printf("ERR:NETLINK read failed!\n");
657         terminate_flag++;
658         return UAP_FAILURE;
659     }
660 #if DEBUG
661     printf("DBG:Received message payload (%d)\n", count);
662 #endif
663     if (count > NLMSG_SPACE(NL_MAX_PAYLOAD)) {
664         printf("ERR:Buffer overflow!\n");
665         return UAP_FAILURE;
666     }
667     bzero(buffer, NL_MAX_PAYLOAD);
668     memcpy(buffer, NLMSG_DATA(nlh), count - NLMSG_HDRLEN);
669 #if DEBUG
670     hexdump(buffer, count - NLMSG_HDRLEN, ' ');
671 #endif
672     return count - NLMSG_HDRLEN;
673 }
674
675 /** 
676  *  @brief Configure and read event data from netlink socket
677  *
678  *  @param sk_fd    Netlink socket handler
679  *  @param buffer   Pointer to the data buffer
680  *  @param timeout  Socket listen timeout value
681  *  @param nlh      Pointer to netlink message header
682  *  @param msg      Pointer to message header
683  *  @return         Number of bytes read or UAP_FAILURE
684  */
685 int
686 read_event(int sk_fd, unsigned char *buffer, int timeout, struct nlmsghdr *nlh,
687            struct msghdr *msg)
688 {
689     struct timeval tv;
690     fd_set rfds;
691     int ret = UAP_FAILURE;
692
693     /* Setup read fds */
694     FD_ZERO(&rfds);
695     FD_SET(sk_fd, &rfds);
696
697     /* Initialize timeout value */
698     if (timeout != 0)
699         tv.tv_sec = timeout;
700     else
701         tv.tv_sec = UAP_RECV_WAIT_DEFAULT;
702     tv.tv_usec = 0;
703
704     /* Wait for reply */
705     ret = select(sk_fd + 1, &rfds, NULL, NULL, &tv);
706     if (ret == -1) {
707         /* Error */
708         terminate_flag++;
709         return UAP_FAILURE;
710     } else if (!ret) {
711         /* Timeout. Try again */
712         return UAP_FAILURE;
713     }
714     if (!FD_ISSET(sk_fd, &rfds)) {
715         /* Unexpected error. Try again */
716         return UAP_FAILURE;
717     }
718
719     /* Success */
720     ret = read_event_netlink_socket(sk_fd, buffer, nlh, msg);
721     return ret;
722 }
723
724 /* Command line options */
725 static const struct option long_opts[] = {
726     {"help", no_argument, NULL, 'h'},
727     {"version", no_argument, NULL, 'v'},
728     {NULL, 0, NULL, 0}
729 };
730
731 /****************************************************************************
732         Global functions
733 ****************************************************************************/
734 /** 
735  *  @brief The main function
736  *  
737  *  @param argc     Number of arguments
738  *  @param argv     Pointer to the arguments
739  *  @return         0 or 1
740  */
741 int
742 main(int argc, char *argv[])
743 {
744     int opt;
745     int nl_sk = 0;
746     struct nlmsghdr *nlh = NULL;
747     struct sockaddr_nl src_addr, dest_addr;
748     struct msghdr msg;
749     struct iovec iov;
750     unsigned char *buffer = NULL;
751     struct timeval current_time;
752     struct tm *timeinfo;
753     int num_events = 0;
754     EVENTHEADER *event = NULL;
755     int ret = UAP_FAILURE;
756
757     /* Check command line options */
758     while ((opt = getopt_long(argc, argv, "hvt", long_opts, NULL)) > 0) {
759         switch (opt) {
760         case 'h':
761             print_usage();
762             return 0;
763         case 'v':
764             printf("uapevent version : %s\n", UAP_VERSION);
765             return 0;
766             break;
767         default:
768             print_usage();
769             return 1;
770         }
771     }
772     if (optind < argc) {
773         fputs("Too many arguments.\n", stderr);
774         print_usage();
775         return 1;
776     }
777
778     /* Open netlink socket */
779     nl_sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_MARVELL);
780     if (nl_sk < 0) {
781         printf("ERR:Could not open netlink socket.\n");
782         ret = UAP_FAILURE;
783         goto done;
784     }
785
786     /* Set source address */
787     bzero((char *) &src_addr, sizeof(src_addr));
788     src_addr.nl_family = AF_NETLINK;
789     src_addr.nl_pid = getpid(); /* Our PID */
790     src_addr.nl_groups = NL_MULTICAST_GROUP;
791
792     /* Bind socket with source address */
793     if (bind(nl_sk, (struct sockaddr *) &src_addr, sizeof(src_addr)) < 0) {
794         printf("ERR:Could not bind socket!\n");
795         ret = UAP_FAILURE;
796         goto done;
797     }
798
799     /* Set destination address */
800     memset(&dest_addr, 0, sizeof(dest_addr));
801     dest_addr.nl_family = AF_NETLINK;
802     dest_addr.nl_pid = 0;       /* Kernel */
803     dest_addr.nl_groups = NL_MULTICAST_GROUP;
804
805     /* Initialize netlink header */
806     nlh = (struct nlmsghdr *) malloc(NLMSG_SPACE(NL_MAX_PAYLOAD));
807     if (!nlh) {
808         printf("ERR: Could not alloc buffer\n");
809         ret = UAP_FAILURE;
810         goto done;
811     }
812     memset(nlh, 0, NLMSG_SPACE(NL_MAX_PAYLOAD));
813
814     /* Initialize I/O vector */
815     iov.iov_base = (void *) nlh;
816     iov.iov_len = NLMSG_SPACE(NL_MAX_PAYLOAD);
817
818     /* Initialize message header */
819     memset(&msg, 0, sizeof(struct msghdr));
820     msg.msg_name = (void *) &dest_addr;
821     msg.msg_namelen = sizeof(dest_addr);
822     msg.msg_iov = &iov;
823     msg.msg_iovlen = 1;
824
825     /* Initialize receive buffer */
826     buffer = malloc(NL_MAX_PAYLOAD);
827     if (!buffer) {
828         printf("ERR: Could not alloc buffer\n");
829         ret = UAP_FAILURE;
830         goto done;
831     }
832     bzero(buffer, sizeof(buffer));
833
834     gettimeofday(&current_time, NULL);
835
836     printf("\n");
837     printf("*********************************************\n");
838     if ((timeinfo = localtime(&(current_time.tv_sec))))
839         printf("uapevent start time : %s", asctime(timeinfo));
840     printf("                      %u usecs\n",
841            (unsigned int) current_time.tv_usec);
842     printf("*********************************************\n");
843
844     signal(SIGTERM, sig_handler);
845     signal(SIGINT, sig_handler);
846     signal(SIGALRM, sig_handler);
847     while (1) {
848         if (terminate_flag) {
849             printf("Stopping!\n");
850             break;
851         }
852         ret = read_event(nl_sk, buffer, 0, nlh, &msg);
853
854         /* No result. Loop again */
855         if (ret == UAP_FAILURE) {
856             continue;
857         }
858         if (ret == 0) {
859             /* Zero bytes received */
860             printf("ERR:Received zero bytes!\n");
861             continue;
862         }
863         num_events++;
864         gettimeofday(&current_time, NULL);
865         printf("\n");
866         printf("============================================\n");
867         printf("Received event");
868         if ((timeinfo = localtime(&(current_time.tv_sec))))
869             printf(": %s", asctime(timeinfo));
870         printf("                     %u usecs\n",
871                (unsigned int) current_time.tv_usec);
872         printf("============================================\n");
873         event = (EVENTHEADER *) buffer;
874         event->EventId = uap_le32_to_cpu(event->EventId);
875 #if DEBUG
876         printf("DBG:Received buffer =\n");
877         hexdump(buffer, ret, ' ');
878 #endif
879         print_event(event, ret);
880         fflush(stdout);
881     }
882     gettimeofday(&current_time, NULL);
883     printf("\n");
884     printf("********************************************\n");
885     if ((timeinfo = localtime(&(current_time.tv_sec))))
886         printf("uapevent end time  : %s", asctime(timeinfo));
887     printf("                     %u usecs\n",
888            (unsigned int) current_time.tv_usec);
889     printf("Total events       : %u\n", num_events);
890     printf("********************************************\n");
891   done:
892     if (buffer)
893         free(buffer);
894     if (nl_sk)
895         close(nl_sk);
896     if (nlh)
897         free(nlh);
898     return 0;
899 }