2 * Application-specific portion of EAPD
5 * Copyright (C) 2010, Broadcom Corporation
8 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
9 * the contents of this file may not be disclosed to third parties, copied
10 * or duplicated in any form, in whole or in part, without the prior
11 * written permission of Broadcom Corporation.
13 * $Id: nas_eap.c 241391 2011-02-18 03:35:48Z stakita $
20 #include <sys/types.h>
21 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
27 #include <proto/ethernet.h>
28 #include <proto/eapol.h>
29 #include <proto/eap.h>
30 #include <bcmendian.h>
36 #include <security_ipc.h>
39 /* mapping from WPA_CIPHER_XXXX to wsec */
40 #define NAS_APP_WPA_CIPHER2WSEC(cipher) ((cipher) == WPA_CIPHER_WEP_40 ? WEP_ENABLED : \
41 (cipher) == WPA_CIPHER_WEP_104 ? WEP_ENABLED : \
42 (cipher) == WPA_CIPHER_TKIP ? TKIP_ENABLED : \
43 (cipher) == WPA_CIPHER_AES_CCM ? AES_ENABLED : \
47 nas_app_wpa_akm2auth(uint32 akm
)
52 case RSN_AKM_UNSPECIFIED
:
53 return WPA_AUTH_UNSPECIFIED
;
62 nas_app_wpa2_akm2auth(uint32 akm
)
67 case RSN_AKM_UNSPECIFIED
:
68 return WPA2_AUTH_UNSPECIFIED
;
77 nas_app_wpa_auth2mode(int auth
)
82 case WPA_AUTH_UNSPECIFIED
:
87 case WPA2_AUTH_UNSPECIFIED
:
90 case WPA_AUTH_DISABLED
:
97 nas_app_is_wpa_ie(uint8
*ie
, uint8
**tlvs
, uint
*tlvs_len
)
99 /* If the contents match the WPA_OUI and type=1 */
100 if ((ie
[TLV_LEN_OFF
] > (WPA_OUI_LEN
+1)) &&
101 !bcmp(&ie
[TLV_BODY_OFF
], WPA_OUI
"\x01", WPA_OUI_LEN
+ 1)) {
105 /* point to the next ie */
106 ie
+= ie
[TLV_LEN_OFF
] + TLV_HDR_LEN
;
107 /* calculate the length of the rest of the buffer */
108 *tlvs_len
-= (int)(ie
- *tlvs
);
109 /* update the pointer to the start of the buffer */
116 nas_app_is_wps_ie(uint8
*ie
, uint8
**tlvs
, uint
*tlvs_len
)
118 /* If the contents match the WPA_OUI and type=4 */
119 if ((ie
[TLV_LEN_OFF
] > (WPA_OUI_LEN
+1)) &&
120 !bcmp(&ie
[TLV_BODY_OFF
], WPA_OUI
"\x04", WPA_OUI_LEN
+ 1)) {
124 /* point to the next ie */
125 ie
+= ie
[TLV_LEN_OFF
] + TLV_HDR_LEN
;
126 /* calculate the length of the rest of the buffer */
127 *tlvs_len
-= (int)(ie
- *tlvs
);
128 /* update the pointer to the start of the buffer */
135 nas_app_parse_tlvs(void *buf
, int buflen
, uint key
)
140 elt
= (bcm_tlv_t
*)buf
;
143 /* find tagged parameter */
144 while (totlen
>= 2) {
147 /* validate remaining totlen */
148 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
151 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ 2));
158 static wpa_ie_fixed_t
*
159 nas_app_find_wpaie(uint8
*parse
, uint len
)
163 while ((ie
= nas_app_parse_tlvs(parse
, len
, DOT11_MNG_WPA_ID
))) {
164 if (nas_app_is_wpa_ie((uint8
*)ie
, &parse
, &len
)) {
165 return (wpa_ie_fixed_t
*)ie
;
171 static wpa_ie_fixed_t
*
172 nas_app_find_wpsie(uint8
*parse
, uint len
)
176 while ((ie
= nas_app_parse_tlvs(parse
, len
, DOT11_MNG_WPA_ID
))) {
177 if (nas_app_is_wps_ie((uint8
*)ie
, &parse
, &len
)) {
178 return (wpa_ie_fixed_t
*)ie
;
184 /* decode WPA IE to retrieve supplicant wsec, auth mode, and pmk cached */
185 /* pmkc - 0:no pmkid in ie, -1:pmkid not found, 1:pmkid found */
187 nas_app_parse_ie(uint8
*ie
, int ie_len
, uint32
*wsec
, uint32
*mode
)
190 wpa_suite_mcast_t
*mcast
= NULL
;
191 wpa_suite_ucast_t
*ucast
= NULL
;
192 wpa_suite_auth_key_mgmt_t
*mgmt
= NULL
;
197 uint32 (*akm2auth
)(uint32 akm
) = NULL
;
198 wpa_ie_fixed_t
*wpaie
= NULL
;
200 int parse_len
= ie_len
;
203 if (nas_app_find_wpsie(parse
, parse_len
))
207 wpaie
= nas_app_find_wpaie(parse
, parse_len
);
211 wpaie
= (wpa_ie_fixed_t
*)nas_app_parse_tlvs(ie
, ie_len
, DOT11_MNG_RSN_ID
);
214 /* No WPA or RSN IE */
218 /* type specific header processing */
219 switch (wpaie
->tag
) {
221 case DOT11_MNG_RSN_ID
: {
222 wpa_rsn_ie_fixed_t
*rsnie
= (wpa_rsn_ie_fixed_t
*)wpaie
;
223 if (rsnie
->length
< WPA_RSN_IE_TAG_FIXED_LEN
) {
224 EAPD_ERROR("invalid RSN IE header\n");
227 if (ltoh16_ua((uint8
*)&rsnie
->version
) != WPA2_VERSION
) {
228 EAPD_ERROR("unsupported RSN IE version\n");
231 mcast
= (wpa_suite_mcast_t
*)(rsnie
+ 1);
232 len
= ie_len
- WPA_RSN_IE_FIXED_LEN
;
233 oui
= (uint8
*)WPA2_OUI
;
234 akm2auth
= nas_app_wpa2_akm2auth
;
238 case DOT11_MNG_WPA_ID
: {
239 if (wpaie
->length
< WPA_IE_TAG_FIXED_LEN
||
240 bcmp(wpaie
->oui
, WPA_OUI
"\x01", WPA_IE_OUITYPE_LEN
)) {
241 EAPD_ERROR("invalid WPA IE header\n");
244 if (ltoh16_ua((uint8
*)&wpaie
->version
) != WPA_VERSION
) {
245 EAPD_ERROR("unsupported WPA IE version\n");
248 mcast
= (wpa_suite_mcast_t
*)(wpaie
+ 1);
249 len
= ie_len
- WPA_IE_FIXED_LEN
;
250 oui
= (uint8
*)WPA_OUI
;
251 akm2auth
= nas_app_wpa_akm2auth
;
255 EAPD_ERROR("unsupported IE type\n");
260 /* init return values - no mcast cipher and no ucast cipher */
266 /* Check for multicast suite */
267 if (len
>= WPA_SUITE_LEN
) {
268 if (!bcmp(mcast
->oui
, oui
, DOT11_OUI_LEN
)) {
270 *wsec
|= NAS_APP_WPA_CIPHER2WSEC(mcast
->type
);
272 len
-= WPA_SUITE_LEN
;
274 /* Check for unicast suite(s) */
275 if (len
>= WPA_IE_SUITE_COUNT_LEN
) {
276 ucast
= (wpa_suite_ucast_t
*)&mcast
[1];
277 count
= ltoh16_ua((uint8
*)&ucast
->count
);
278 len
-= WPA_IE_SUITE_COUNT_LEN
;
280 EAPD_ERROR("# of unicast cipher suites %d\n", count
);
283 if (!bcmp(ucast
->list
[0].oui
, oui
, DOT11_OUI_LEN
)) {
285 *wsec
|= NAS_APP_WPA_CIPHER2WSEC(ucast
->list
[0].type
);
287 len
-= WPA_SUITE_LEN
;
289 /* Check for auth key management suite(s) */
290 if (len
>= WPA_IE_SUITE_COUNT_LEN
) {
291 mgmt
= (wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[1];
292 count
= ltoh16_ua((uint8
*)&mgmt
->count
);
293 len
-= WPA_IE_SUITE_COUNT_LEN
;
295 EAPD_ERROR("# of AKM suites %d\n", count
);
298 if (!bcmp(mgmt
->list
[0].oui
, oui
, DOT11_OUI_LEN
)) {
299 m
= nas_app_wpa_auth2mode(akm2auth(mgmt
->list
[0].type
));
303 len
-= WPA_SUITE_LEN
;
305 EAPD_INFO("wsec 0x%x mode 0x%x\n", *wsec
, *mode
);
310 /* Receive eapol, preauth message from nas module
313 nas_app_recv_handler(eapd_wksp_t
*nwksp
, char *wlifname
, eapd_cb_t
*from
, uint8
*pData
,
316 eapol_header_t
*eapol
= (eapol_header_t
*) pData
;
318 struct ether_addr
*sta_ea
;
320 struct eapd_socket
*Socket
= NULL
;
322 if (!nwksp
|| !wlifname
|| !from
|| !pData
) {
323 EAPD_ERROR("Wrong argument...\n");
327 if (*pLen
< EAPOL_HEADER_LEN
)
328 return; /* message too short */
330 /* dispatch message to eapol, preauth and brcmevent */
331 switch (ntohs(eapol
->eth
.ether_type
)) {
332 case ETHER_TYPE_802_1X
: /* eapol */
333 case ETHER_TYPE_BRCM
: /* brcmevent */
334 Socket
= from
->brcmSocket
;
337 case ETHER_TYPE_802_1X_PREAUTH
: /* preauth */
338 Socket
= &from
->preauthSocket
;
343 /* send message data out. */
344 sta_ea
= (struct ether_addr
*) eapol
->eth
.ether_dhost
;
345 sta
= sta_lookup(nwksp
, sta_ea
, NULL
, wlifname
, EAPD_SEARCH_ONLY
);
347 /* monitor eapol packet */
348 eap
= (eap_header_t
*) eapol
->body
;
349 if ((sta
) && (eapol
->type
== EAP_PACKET
) &&
350 (eap
->code
== EAP_FAILURE
|| eap
->code
== EAP_SUCCESS
)) {
351 sta_remove(nwksp
, sta
);
354 if (Socket
!= NULL
) {
355 eapd_message_send(nwksp
, Socket
, pData
, *pLen
);
358 EAPD_ERROR("Socket is not exist!\n");
364 nas_app_set_eventmask(eapd_app_t
*app
)
366 memset(app
->bitvec
, 0, sizeof(app
->bitvec
));
368 setbit(app
->bitvec
, WLC_E_EAPOL_MSG
);
369 setbit(app
->bitvec
, WLC_E_LINK
);
370 setbit(app
->bitvec
, WLC_E_ASSOC_IND
);
371 setbit(app
->bitvec
, WLC_E_REASSOC_IND
);
372 setbit(app
->bitvec
, WLC_E_DISASSOC_IND
);
373 setbit(app
->bitvec
, WLC_E_DEAUTH_IND
);
374 setbit(app
->bitvec
, WLC_E_MIC_ERROR
);
379 nas_app_init(eapd_wksp_t
*nwksp
)
385 eapd_preauth_socket_t
*preauthSocket
;
387 struct sockaddr_in addr
;
398 EAPD_INFO("No any NAS application need to run.\n");
403 EAPD_INFO("nas: init brcm interface %s \n", cb
->ifname
);
404 cb
->brcmSocket
= eapd_add_brcm(nwksp
, cb
->ifname
);
407 /* set this brcmSocket have NAS capability */
408 cb
->brcmSocket
->flag
|= EAPD_CAP_NAS
;
411 /* open preauth socket */
412 preauthSocket
= &cb
->preauthSocket
;
413 memset(preauthSocket
, 0, sizeof(eapd_preauth_socket_t
));
414 strcpy(preauthSocket
->ifname
, cb
->ifname
);
415 EAPD_INFO("nas: init preauth interface %s \n", cb
->ifname
);
416 if (eapd_preauth_open(nwksp
, preauthSocket
) < 0) {
417 EAPD_ERROR("open preauth socket on %s error!!\n", preauthSocket
->ifname
);
418 preauthSocket
->drvSocket
= -1;
424 /* appSocket for nas */
425 nas
->appSocket
= socket(AF_INET
, SOCK_DGRAM
, 0);
426 if (nas
->appSocket
< 0) {
427 EAPD_ERROR("UDP Open failed.\n");
431 if (setsockopt(nas
->appSocket
, SOL_SOCKET
, SO_REUSEPORT
, (char*)&reuse
,
432 sizeof(reuse
)) < 0) {
433 EAPD_ERROR("UDP setsockopt failed.\n");
434 close(nas
->appSocket
);
439 if (setsockopt(nas
->appSocket
, SOL_SOCKET
, SO_REUSEADDR
, (char*)&reuse
,
440 sizeof(reuse
)) < 0) {
441 EAPD_ERROR("UDP setsockopt failed.\n");
442 close(nas
->appSocket
);
448 memset(&addr
, 0, sizeof(struct sockaddr_in
));
449 addr
.sin_family
= AF_INET
;
450 addr
.sin_addr
.s_addr
= INADDR_ANY
;
451 addr
.sin_port
= htons(EAPD_WKSP_NAS_UDP_RPORT
);
452 if (bind(nas
->appSocket
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
453 EAPD_ERROR("UDP Bind failed, close nas appSocket %d\n", nas
->appSocket
);
454 close(nas
->appSocket
);
458 EAPD_INFO("NAS appSocket %d opened\n", nas
->appSocket
);
464 nas_app_deinit(eapd_wksp_t
*nwksp
)
467 eapd_cb_t
*cb
, *tmp_cb
;
469 eapd_preauth_socket_t
*preauthSocket
;
473 EAPD_ERROR("Wrong argument...\n");
480 /* close brcm drvSocket */
481 if (cb
->brcmSocket
) {
482 EAPD_INFO("close nas brcmSocket %d\n", cb
->brcmSocket
->drvSocket
);
483 eapd_del_brcm(nwksp
, cb
->brcmSocket
);
487 /* close preauth drvSocket */
488 preauthSocket
= &cb
->preauthSocket
;
489 if (preauthSocket
->drvSocket
>= 0) {
490 EAPD_INFO("close nas preauthSocket %d\n", preauthSocket
->drvSocket
);
491 eapd_preauth_close(preauthSocket
->drvSocket
);
492 preauthSocket
->drvSocket
= -1;
501 if (nas
->appSocket
>= 0) {
502 EAPD_INFO("close nas appSocket %d\n", nas
->appSocket
);
503 close(nas
->appSocket
);
510 /* nas_sendup will send eapol, brcm and preauth packet */
512 nas_app_sendup(eapd_wksp_t
*nwksp
, uint8
*pData
, int pLen
, char *from
)
517 EAPD_ERROR("Wrong argument...\n");
522 if (nas
->appSocket
>= 0) {
525 struct sockaddr_in to
;
527 to
.sin_addr
.s_addr
= inet_addr(EAPD_WKSP_UDP_ADDR
);
528 to
.sin_family
= AF_INET
;
529 to
.sin_port
= htons(EAPD_WKSP_NAS_UDP_SPORT
);
531 sentBytes
= sendto(nas
->appSocket
, (char *)pData
, pLen
, 0,
532 (struct sockaddr
*)&to
, sizeof(struct sockaddr_in
));
534 if (sentBytes
!= pLen
) {
535 EAPD_ERROR("UDP send failed; sentBytes = %d\n", sentBytes
);
538 /* EAPD_ERROR("Send %d bytes to nas\n", sentBytes); */
542 EAPD_ERROR("nas appSocket not created\n");
547 #if EAPD_WKSP_AUTO_CONFIG
549 nas_app_enabled(char *name
)
551 char value
[128], comb
[32], akm
[16], prefix
[8];
552 char akms
[128], auth
[32], wep
[32], crypto
[32], os_name
[IFNAMSIZ
];
557 memset(os_name
, 0, sizeof(os_name
));
559 if (nvifname_to_osifname(name
, os_name
, sizeof(os_name
)))
561 if (wl_probe(os_name
) ||
562 wl_ioctl(os_name
, WLC_GET_INSTANCE
, &unit
, sizeof(unit
)))
564 if (osifname_to_nvifname(name
, prefix
, sizeof(prefix
)))
568 /* ignore if disabled */
569 eapd_safe_get_conf(value
, sizeof(value
), strcat_r(prefix
, "radio", comb
));
570 if (atoi(value
) == 0) {
571 EAPD_INFO("NAS:ignored interface %s. radio disabled\n", os_name
);
575 eapd_safe_get_conf(value
, sizeof(value
), strcat_r(prefix
, "auth", comb
));
576 if (atoi(value
) == 1) {
577 EAPD_INFO("NAS: ignored interface %s. Shared 802.11 auth\n", os_name
);
580 /* ignore if BSS is disabled */
581 eapd_safe_get_conf(value
, sizeof(value
), strcat_r(prefix
, "bss_enabled", comb
));
582 if (atoi(value
) == 0) {
583 EAPD_INFO("NAS: ignored interface %s, %s is disabled \n", os_name
, comb
);
587 eapd_safe_get_conf(auth
, sizeof(auth
), strcat_r(prefix
, "auth_mode", comb
));
588 nasm
= !strcmp(auth
, "radius") ? RADIUS
: 0;
589 eapd_safe_get_conf(akms
, sizeof(akms
), strcat_r(prefix
, "akm", comb
));
590 foreach(akm
, akms
, akmnext
) {
591 if (!strcmp(akm
, "wpa"))
593 if (!strcmp(akm
, "psk"))
596 if (!strcmp(akm
, "wpa2"))
598 if (!strcmp(akm
, "psk2"))
603 EAPD_INFO("NAS:ignored interface %s. Invalid NAS mode\n", os_name
);
607 eapd_safe_get_conf(wep
, sizeof(wep
), strcat_r(prefix
, "wep", comb
));
608 wsec
= !strcmp(wep
, "enabled") ? WEP_ENABLED
: 0;
609 if (CHECK_NAS(nasm
)) {
610 eapd_safe_get_conf(crypto
, sizeof(crypto
), strcat_r(prefix
, "crypto", comb
));
611 if (!strcmp(crypto
, "tkip"))
612 wsec
|= TKIP_ENABLED
;
613 else if (!strcmp(crypto
, "aes"))
615 else if (!strcmp(crypto
, "tkip+aes"))
616 wsec
|= TKIP_ENABLED
|AES_ENABLED
;
619 EAPD_INFO("%s: Ignored interface. Invalid WSEC\n", os_name
);
623 /* if come to here return enabled */
626 #endif /* EAPD_WKSP_AUTO_CONFIG */
629 nas_app_handle_event(eapd_wksp_t
*nwksp
, uint8
*pData
, int Len
, char *from
)
634 bcm_event_t
*dpkt
= (bcm_event_t
*) pData
;
635 wl_event_msg_t
*event
= &(dpkt
->event
);
636 uint8
*addr
= (uint8
*)&(event
->addr
);
637 uint8
*data
= (uint8
*)(event
+ 1);
638 uint16 len
= ntoh32(event
->datalen
);
643 type
= ntohl(event
->event_type
);
648 if (isset(nas
->bitvec
, type
) &&
649 !strcmp(cb
->ifname
, from
)) {
650 /* We need to know is client in PSK mode */
651 if (type
== WLC_E_ASSOC_IND
|| type
== WLC_E_REASSOC_IND
||
652 type
== WLC_E_DISASSOC_IND
|| type
== WLC_E_DEAUTH_IND
) {
653 sta
= sta_lookup(nwksp
, (struct ether_addr
*)addr
,
654 (struct ether_addr
*) dpkt
->eth
.ether_dhost
,
655 event
->ifname
, EAPD_SEARCH_ENTER
);
657 EAPD_ERROR("no STA struct available\n");
661 if (type
== WLC_E_DISASSOC_IND
|| type
== WLC_E_DEAUTH_IND
) {
662 /* Reset the sta mode */
663 sta
->mode
= EAPD_STA_MODE_UNKNOW
;
665 else if (!nas_app_parse_ie(data
, len
, &wsec
, &mode
) &&
667 /* set cient in PSK mode */
668 sta
->mode
= EAPD_STA_MODE_NAS_PSK
;
672 /* prepend ifname, we reserved IFNAMSIZ length already */
675 memcpy(pData
, event
->ifname
, IFNAMSIZ
);
677 /* send to nas use cb->ifname */
678 nas_app_sendup(nwksp
, pData
, Len
, cb
->ifname
);