Cumulative patch from commit d3b204694a39e6c57a4c6689b87f4192e1b93a06
d3b2046 P2P: Make the default p2p_find delay value configurable
3dacd3e atheros: Add support for new GCMP/CCMP/CMAC/GMAC cipher suites
737754d EAP-IKEv2: Remove obsolete ccns.pl project workarounds
aa6bf6d eap_proxy: Check sm != NULL more consistently
4f4d51e TDLS: Add extra validation step for responder RSN IE length
a01acc5 Check for EVENT_ASSOC data to be present for AP mode operation
1fde15a GAS server: Explicitly check that home realm is available
aff0bee GAS server: Remove unused function parameter
86388af WPS: Check for theoretical gmtime() failure
d75a5ae WPS ER: Fix UDN parser to handle missing field
0bbaa9b Validate driver extended capabilities length against buffer length
9c6c558 Interworking: Reject EAP configuration with unsupported inner method
f2ca0e9 Check eap_get_name() return against NULL to silence static analyzer
bc32bb7 Make a code path easier for static analyzers to understand
fb958ea Check current_ssid on unexpected association event
2a57c33 Reserve QCA vendor specific nl80211 commands 20..33
84df167 nl80211: Add vendor attribute for interface index
9949483 The master branch is now used for v2.3 development
Change-Id: Ib39c204aaa3ebcc909057f815e5e291e15e5df88
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 2a4acf2..73dffe2 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -220,7 +220,7 @@
continue; /* can use same entry */
}
- if (start) {
+ if (start && prev) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
start = NULL;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index b406880..52d1b24 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -414,7 +414,7 @@
gas_anqp_set_element_len(buf, realm_data_len);
}
gas_anqp_set_element_len(buf, len);
- } else if (nai_home_realm && hapd->conf->nai_realm_data) {
+ } else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) {
hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
home_realm_len);
}
@@ -686,7 +686,6 @@
static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
- struct gas_dialog_info *di,
const u8 *home_realm, size_t home_realm_len,
const u8 *icon_name, size_t icon_name_len)
{
@@ -962,7 +961,7 @@
{
struct wpabuf *buf, *tx_buf;
- buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
+ buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
qi->home_realm_query,
qi->home_realm_query_len,
qi->icon_name, qi->icon_name_len);
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index a56b188..4d9efd5 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -52,7 +52,7 @@
QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11,
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
- /* 14..19 - reserved for QCA */
+ /* 14..33 - reserved for QCA */
};
@@ -64,6 +64,8 @@
QCA_WLAN_VENDOR_ATTR_NAN = 2,
/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
+ QCA_WLAN_VENDOR_ATTR_IFINDEX = 4,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
diff --git a/src/common/version.h b/src/common/version.h
index 340afc7..1f25432 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
-#define VERSION_STR "2.2" VERSION_STR_POSTFIX
+#define VERSION_STR "2.3-devel" VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index c146cdc..b569a0a 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -260,6 +260,17 @@
case WPA_CIPHER_CCMP:
v = IEEE80211_CIPHER_AES_CCM;
break;
+#ifdef ATH_GCM_SUPPORT
+ case WPA_CIPHER_CCMP_256:
+ v = IEEE80211_CIPHER_AES_CCM_256;
+ break;
+ case WPA_CIPHER_GCMP:
+ v = IEEE80211_CIPHER_AES_GCM;
+ break;
+ case WPA_CIPHER_GCMP_256:
+ v = IEEE80211_CIPHER_AES_GCM_256;
+ break;
+#endif /* ATH_GCM_SUPPORT */
case WPA_CIPHER_TKIP:
v = IEEE80211_CIPHER_TKIP;
break;
@@ -294,6 +305,14 @@
v = 0;
if (params->wpa_pairwise & WPA_CIPHER_CCMP)
v |= 1<<IEEE80211_CIPHER_AES_CCM;
+#ifdef ATH_GCM_SUPPORT
+ if (params->wpa_pairwise & WPA_CIPHER_CCMP_256)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM_256;
+ if (params->wpa_pairwise & WPA_CIPHER_GCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_GCM;
+ if (params->wpa_pairwise & WPA_CIPHER_GCMP_256)
+ v |= 1<<IEEE80211_CIPHER_AES_GCM_256;
+#endif /* ATH_GCM_SUPPORT */
if (params->wpa_pairwise & WPA_CIPHER_TKIP)
v |= 1<<IEEE80211_CIPHER_TKIP;
if (params->wpa_pairwise & WPA_CIPHER_NONE)
@@ -471,10 +490,32 @@
case WPA_ALG_CCMP:
cipher = IEEE80211_CIPHER_AES_CCM;
break;
+#ifdef ATH_GCM_SUPPORT
+ case WPA_ALG_CCMP_256:
+ cipher = IEEE80211_CIPHER_AES_CCM_256;
+ break;
+ case WPA_ALG_GCMP:
+ cipher = IEEE80211_CIPHER_AES_GCM;
+ break;
+ case WPA_ALG_GCMP_256:
+ cipher = IEEE80211_CIPHER_AES_GCM_256;
+ break;
+#endif /* ATH_GCM_SUPPORT */
#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
cipher = IEEE80211_CIPHER_AES_CMAC;
break;
+#ifdef ATH_GCM_SUPPORT
+ case WPA_ALG_BIP_CMAC_256:
+ cipher = IEEE80211_CIPHER_AES_CMAC_256;
+ break;
+ case WPA_ALG_BIP_GMAC_128:
+ cipher = IEEE80211_CIPHER_AES_GMAC;
+ break;
+ case WPA_ALG_BIP_GMAC_256:
+ cipher = IEEE80211_CIPHER_AES_GMAC_256;
+ break;
+#endif /* ATH_GCM_SUPPORT */
#endif /* CONFIG_IEEE80211W */
default:
printf("%s: unknown/unsupported algorithm %d\n",
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 7e175f4..40aaba5 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -105,6 +105,9 @@
CONFIG_L2_PACKET=linux
NEED_NETLINK=y
NEED_LINUX_IOCTL=y
+ifdef ATH_GCM_SUPPORT
+CFLAGS += -DATH_GCM_SUPPORT
+endif
endif
##### PURE CLIENT DRIVERS
diff --git a/src/eap_common/eap_ikev2_common.c b/src/eap_common/eap_ikev2_common.c
index 6095fd8..da9f3cc 100644
--- a/src/eap_common/eap_ikev2_common.c
+++ b/src/eap_common/eap_ikev2_common.c
@@ -52,22 +52,12 @@
{
struct wpabuf *msg;
-#ifdef CCNS_PL
- msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id);
- if (msg == NULL) {
- wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
- "for fragment ack");
- return NULL;
- }
- wpabuf_put_u8(msg, 0); /* Flags */
-#else /* CCNS_PL */
msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
if (msg == NULL) {
wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
"for fragment ack");
return NULL;
}
-#endif /* CCNS_PL */
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
diff --git a/src/eap_common/eap_ikev2_common.h b/src/eap_common/eap_ikev2_common.h
index 329ccc4..e7502d7 100644
--- a/src/eap_common/eap_ikev2_common.h
+++ b/src/eap_common/eap_ikev2_common.h
@@ -9,16 +9,9 @@
#ifndef EAP_IKEV2_COMMON_H
#define EAP_IKEV2_COMMON_H
-#ifdef CCNS_PL
-/* incorrect bit order */
-#define IKEV2_FLAGS_LENGTH_INCLUDED 0x01
-#define IKEV2_FLAGS_MORE_FRAGMENTS 0x02
-#define IKEV2_FLAGS_ICV_INCLUDED 0x04
-#else /* CCNS_PL */
#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80
#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40
#define IKEV2_FLAGS_ICV_INCLUDED 0x20
-#endif /* CCNS_PL */
#define IKEV2_FRAGMENT_SIZE 1400
diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c
index f061866..b98a3e8 100644
--- a/src/eap_common/ikev2_common.c
+++ b/src/eap_common/ikev2_common.c
@@ -173,46 +173,12 @@
}
-#ifdef CCNS_PL
-/* from des.c */
-struct des3_key_s {
- u32 ek[3][32];
- u32 dk[3][32];
-};
-
-void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
-void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
-void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
-#endif /* CCNS_PL */
-
-
int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
const u8 *plain, u8 *crypt, size_t len)
{
struct crypto_cipher *cipher;
int encr_alg;
-#ifdef CCNS_PL
- if (alg == ENCR_3DES) {
- struct des3_key_s des3key;
- size_t i, blocks;
- u8 *pos;
-
- /* ECB mode is used incorrectly for 3DES!? */
- if (key_len != 24) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
- return -1;
- }
- des3_key_setup(key, &des3key);
-
- blocks = len / 8;
- pos = crypt;
- for (i = 0; i < blocks; i++) {
- des3_encrypt(pos, &des3key, pos);
- pos += 8;
- }
- } else {
-#endif /* CCNS_PL */
switch (alg) {
case ENCR_3DES:
encr_alg = CRYPTO_CIPHER_ALG_3DES;
@@ -237,9 +203,6 @@
return -1;
}
crypto_cipher_deinit(cipher);
-#ifdef CCNS_PL
- }
-#endif /* CCNS_PL */
return 0;
}
@@ -251,31 +214,6 @@
struct crypto_cipher *cipher;
int encr_alg;
-#ifdef CCNS_PL
- if (alg == ENCR_3DES) {
- struct des3_key_s des3key;
- size_t i, blocks;
-
- /* ECB mode is used incorrectly for 3DES!? */
- if (key_len != 24) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
- return -1;
- }
- des3_key_setup(key, &des3key);
-
- if (len % 8) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted "
- "length");
- return -1;
- }
- blocks = len / 8;
- for (i = 0; i < blocks; i++) {
- des3_decrypt(crypt, &des3key, plain);
- plain += 8;
- crypt += 8;
- }
- } else {
-#endif /* CCNS_PL */
switch (alg) {
case ENCR_3DES:
encr_alg = CRYPTO_CIPHER_ALG_3DES;
@@ -300,9 +238,6 @@
return -1;
}
crypto_cipher_deinit(cipher);
-#ifdef CCNS_PL
- }
-#endif /* CCNS_PL */
return 0;
}
@@ -706,10 +641,6 @@
keys->SK_integ_len = integ->key_len;
keys->SK_encr_len = encr->key_len;
keys->SK_prf_len = prf->key_len;
-#ifdef CCNS_PL
- /* Uses encryption key length for SK_d; should be PRF length */
- keys->SK_d_len = keys->SK_encr_len;
-#endif /* CCNS_PL */
keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
diff --git a/src/eap_common/ikev2_common.h b/src/eap_common/ikev2_common.h
index 45c970b..8a7982a 100644
--- a/src/eap_common/ikev2_common.h
+++ b/src/eap_common/ikev2_common.h
@@ -70,11 +70,7 @@
/* Current IKEv2 version from RFC 4306 */
#define IKEV2_MjVer 2
#define IKEV2_MnVer 0
-#ifdef CCNS_PL
-#define IKEV2_VERSION ((IKEV2_MjVer) | ((IKEV2_MnVer) << 4))
-#else /* CCNS_PL */
#define IKEV2_VERSION (((IKEV2_MjVer) << 4) | (IKEV2_MnVer))
-#endif /* CCNS_PL */
/* IKEv2 Exchange Types */
enum {
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index 45945fe..568a448 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -154,12 +154,6 @@
send_len -= 4;
}
}
-#ifdef CCNS_PL
- /* Some issues figuring out the length of the message if Message Length
- * field not included?! */
- if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED))
- flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
-#endif /* CCNS_PL */
plen = 1 + send_len;
if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
@@ -381,12 +375,7 @@
"Message Length %u", flags, message_length);
if (data->state == WAIT_FRAG_ACK) {
-#ifdef CCNS_PL
- if (len > 1) /* Empty Flags field included in ACK */
-#else /* CCNS_PL */
- if (len != 0)
-#endif /* CCNS_PL */
- {
+ if (len != 0) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
"in WAIT_FRAG_ACK state");
ret->ignore = TRUE;
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index 1ccc352..fb2f619 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -72,27 +72,10 @@
os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
pos += IKEV2_SPI_LEN;
os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
-#ifdef CCNS_PL
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- {
- int i;
- u8 *tmp = pos - IKEV2_SPI_LEN;
- /* Incorrect byte re-ordering on little endian hosts.. */
- for (i = 0; i < IKEV2_SPI_LEN; i++)
- *tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i];
- for (i = 0; i < IKEV2_SPI_LEN; i++)
- *tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i];
- }
-#endif
-#endif /* CCNS_PL */
/* SKEYSEED = prf(Ni | Nr, g^ir) */
/* Use zero-padding per RFC 4306, Sect. 2.14 */
pad_len = data->dh->prime_len - wpabuf_len(shared);
-#ifdef CCNS_PL
- /* Shared secret is not zero-padded correctly */
- pad_len = 0;
-#endif /* CCNS_PL */
pad = os_zalloc(pad_len ? pad_len : 1);
if (pad == NULL) {
wpabuf_free(shared);
@@ -179,21 +162,12 @@
"Transform Attr for AES");
break;
}
-#ifdef CCNS_PL
- if (WPA_GET_BE16(pos) != 0x001d /* ?? */) {
- wpa_printf(MSG_DEBUG, "IKEV2: Not a "
- "Key Size attribute for "
- "AES");
- break;
- }
-#else /* CCNS_PL */
if (WPA_GET_BE16(pos) != 0x800e) {
wpa_printf(MSG_DEBUG, "IKEV2: Not a "
"Key Size attribute for "
"AES");
break;
}
-#endif /* CCNS_PL */
if (WPA_GET_BE16(pos + 2) != 128) {
wpa_printf(MSG_DEBUG, "IKEV2: "
"Unsupported AES key size "
@@ -456,14 +430,6 @@
return -1;
}
-#ifdef CCNS_PL
- /* Zeros are removed incorrectly from the beginning of the nonces */
- while (ni_len > 1 && *ni == 0) {
- ni_len--;
- ni++;
- }
-#endif /* CCNS_PL */
-
data->i_nonce_len = ni_len;
os_memcpy(data->i_nonce, ni, ni_len);
wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni",
@@ -887,16 +853,7 @@
phdr->flags = 0;
p = wpabuf_put(msg, sizeof(*p));
-#ifdef CCNS_PL
- /* Seems to require that the Proposal # is 1 even though RFC 4306
- * Sect 3.3.1 has following requirement "When a proposal is accepted,
- * all of the proposal numbers in the SA payload MUST be the same and
- * MUST match the number on the proposal sent that was accepted.".
- */
- p->proposal_num = 1;
-#else /* CCNS_PL */
p->proposal_num = data->proposal.proposal_num;
-#endif /* CCNS_PL */
p->protocol_id = IKEV2_PROTOCOL_IKE;
p->num_transforms = 4;
@@ -906,11 +863,7 @@
WPA_PUT_BE16(t->transform_id, data->proposal.encr);
if (data->proposal.encr == ENCR_AES_CBC) {
/* Transform Attribute: Key Len = 128 bits */
-#ifdef CCNS_PL
- wpabuf_put_be16(msg, 0x001d); /* ?? */
-#else /* CCNS_PL */
wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
-#endif /* CCNS_PL */
wpabuf_put_be16(msg, 128); /* 128-bit key */
}
plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
@@ -1082,11 +1035,7 @@
phdr = wpabuf_put(msg, sizeof(*phdr));
phdr->next_payload = next_payload;
phdr->flags = 0;
-#ifdef CCNS_PL
- wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */
-#else /* CCNS_PL */
wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */
-#endif /* CCNS_PL */
wpabuf_put_u8(msg, 0); /* SPI Size */
wpabuf_put_be16(msg, data->error_type);
@@ -1130,13 +1079,6 @@
data->r_nonce_len = IKEV2_NONCE_MIN_LEN;
if (random_get_bytes(data->r_nonce, data->r_nonce_len))
return NULL;
-#ifdef CCNS_PL
- /* Zeros are removed incorrectly from the beginning of the nonces in
- * key derivation; as a workaround, make sure Nr does not start with
- * zero.. */
- if (data->r_nonce[0] == 0)
- data->r_nonce[0] = 1;
-#endif /* CCNS_PL */
wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len);
msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 1004b1a..e00dea3 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1523,7 +1523,7 @@
size_t eap_len;
#ifdef CONFIG_EAP_PROXY
- if (sm->use_eap_proxy) {
+ if (sm && sm->use_eap_proxy) {
/* Get key from EAP proxy */
if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 3b14656..84b7c1b 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -2098,6 +2098,13 @@
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
kde.rsn_ie, kde.rsn_ie_len);
+ if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
+ wpa_printf(MSG_INFO,
+ "TDLS: Too long Responder RSN IE in TPK M2");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto error;
+ }
+
/*
* FIX: bitwise comparison of RSN IE is not the correct way of
* validation this. It can be different, but certain fields must
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 8b2675e..078ff72 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -579,12 +579,15 @@
wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
ap->udn = xml_get_first_item(data, "UDN");
- wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
- pos = os_strstr(ap->udn, "uuid:");
- if (pos) {
- pos += 5;
- if (uuid_str2bin(pos, ap->uuid) < 0)
- wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN");
+ if (ap->udn) {
+ wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
+ pos = os_strstr(ap->udn, "uuid:");
+ if (pos) {
+ pos += 5;
+ if (uuid_str2bin(pos, ap->uuid) < 0)
+ wpa_printf(MSG_DEBUG,
+ "WPS ER: Invalid UUID in UDN");
+ }
}
ap->upc = xml_get_first_item(data, "UPC");
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 6fb3d4c..f62b49e 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -227,6 +227,8 @@
t = time(NULL);
date = gmtime(&t);
+ if (date == NULL)
+ return;
wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT",
&weekday_str[date->tm_wday * 4], date->tm_mday,
&month_str[date->tm_mon * 4], date->tm_year + 1900,