2 * Received frame processing for wired interface
3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
10 #include <net/ethernet.h>
11 #include <netinet/ip.h>
12 #include <netinet/udp.h>
14 #include "utils/common.h"
15 #include "radius/radius.h"
19 static struct wlantest_radius
* radius_get(struct wlantest
*wt
, u32 srv
,
22 struct wlantest_radius
*r
;
24 dl_list_for_each(r
, &wt
->radius
, struct wlantest_radius
, list
) {
25 if (r
->srv
== srv
&& r
->cli
== cli
)
29 r
= os_zalloc(sizeof(*r
));
35 dl_list_add(&wt
->radius
, &r
->list
);
41 static const char * radius_code_string(u8 code
)
44 case RADIUS_CODE_ACCESS_REQUEST
:
45 return "Access-Request";
46 case RADIUS_CODE_ACCESS_ACCEPT
:
47 return "Access-Accept";
48 case RADIUS_CODE_ACCESS_REJECT
:
49 return "Access-Reject";
50 case RADIUS_CODE_ACCOUNTING_REQUEST
:
51 return "Accounting-Request";
52 case RADIUS_CODE_ACCOUNTING_RESPONSE
:
53 return "Accounting-Response";
54 case RADIUS_CODE_ACCESS_CHALLENGE
:
55 return "Access-Challenge";
56 case RADIUS_CODE_STATUS_SERVER
:
57 return "Status-Server";
58 case RADIUS_CODE_STATUS_CLIENT
:
59 return "Status-Client";
60 case RADIUS_CODE_RESERVED
:
68 static void process_radius_access_request(struct wlantest
*wt
, u32 dst
,
69 u32 src
, const u8
*data
, size_t len
)
71 struct radius_msg
*msg
;
72 struct wlantest_radius
*r
;
74 msg
= radius_msg_parse(data
, len
);
76 wpa_printf(MSG_DEBUG
, "Failed to parse RADIUS Access-Request");
80 r
= radius_get(wt
, dst
, src
);
82 radius_msg_free(r
->last_req
);
90 static void wlantest_add_pmk(struct wlantest
*wt
, const u8
*pmk
, size_t pmk_len
)
92 struct wlantest_pmk
*p
;
94 p
= os_zalloc(sizeof(*p
));
97 os_memcpy(p
->pmk
, pmk
, pmk_len
);
99 dl_list_add(&wt
->pmk
, &p
->list
);
100 wpa_hexdump(MSG_INFO
, "Add PMK", pmk
, pmk_len
);
104 static void process_radius_access_accept(struct wlantest
*wt
, u32 dst
, u32 src
,
105 const u8
*data
, size_t len
)
107 struct radius_msg
*msg
;
108 struct wlantest_radius
*r
;
109 struct radius_ms_mppe_keys
*keys
;
110 struct wlantest_radius_secret
*s
;
112 r
= radius_get(wt
, src
, dst
);
113 if (r
== NULL
|| r
->last_req
== NULL
) {
114 wpa_printf(MSG_DEBUG
, "No RADIUS Access-Challenge found for "
115 "decrypting Access-Accept keys");
119 msg
= radius_msg_parse(data
, len
);
121 wpa_printf(MSG_DEBUG
, "Failed to parse RADIUS Access-Accept");
125 dl_list_for_each(s
, &wt
->secret
, struct wlantest_radius_secret
, list
) {
127 keys
= radius_msg_get_ms_keys(msg
, r
->last_req
,
129 os_strlen(s
->secret
));
130 if (keys
&& keys
->send
&& keys
->recv
) {
132 size_t pmk_len
, len2
;
134 wpa_hexdump_key(MSG_DEBUG
, "MS-MPPE-Send-Key",
135 keys
->send
, keys
->send_len
);
136 wpa_hexdump_key(MSG_DEBUG
, "MS-MPPE-Recv-Key",
137 keys
->recv
, keys
->recv_len
);
138 pmk_len
= keys
->recv_len
;
139 if (pmk_len
> PMK_LEN_MAX
)
140 pmk_len
= PMK_LEN_MAX
;
141 os_memcpy(pmk
, keys
->recv
, pmk_len
);
142 if (pmk_len
< PMK_LEN_MAX
) {
143 len2
= keys
->send_len
;
144 if (pmk_len
+ len2
> PMK_LEN_MAX
)
145 len2
= PMK_LEN_MAX
- pmk_len
;
146 os_memcpy(pmk
+ pmk_len
, keys
->send
, len2
);
149 wlantest_add_pmk(wt
, pmk
, pmk_len
);
163 radius_msg_free(msg
);
167 static void process_radius(struct wlantest
*wt
, u32 dst
, u16 dport
, u32 src
,
168 u16 sport
, const u8
*data
, size_t len
)
172 const struct radius_hdr
*hdr
;
175 if (len
< sizeof(*hdr
))
177 hdr
= (const struct radius_hdr
*) data
;
178 rlen
= be_to_host16(hdr
->length
);
185 snprintf(buf
, sizeof(buf
), "%s", inet_ntoa(addr
));
188 wpa_printf(MSG_DEBUG
, "RADIUS %s:%u -> %s:%u id=%u %s",
189 inet_ntoa(addr
), sport
, buf
, dport
, hdr
->identifier
,
190 radius_code_string(hdr
->code
));
193 case RADIUS_CODE_ACCESS_REQUEST
:
194 process_radius_access_request(wt
, dst
, src
, data
, len
);
196 case RADIUS_CODE_ACCESS_ACCEPT
:
197 process_radius_access_accept(wt
, dst
, src
, data
, len
);
203 static void process_udp(struct wlantest
*wt
, u32 dst
, u32 src
,
204 const u8
*data
, size_t len
)
206 const struct udphdr
*udp
;
207 u16 sport
, dport
, ulen
;
211 if (len
< sizeof(*udp
))
213 udp
= (const struct udphdr
*) data
;
214 /* TODO: check UDP checksum */
215 sport
= be_to_host16(udp
->source
);
216 dport
= be_to_host16(udp
->dest
);
217 ulen
= be_to_host16(udp
->len
);
224 payload
= (const u8
*) (udp
+ 1);
225 plen
= len
- sizeof(*udp
);
227 if (sport
== 1812 || dport
== 1812)
228 process_radius(wt
, dst
, dport
, src
, sport
, payload
, plen
);
232 static void process_ipv4(struct wlantest
*wt
, const u8
*data
, size_t len
)
234 const struct iphdr
*ip
;
237 u16 frag_off
, tot_len
;
239 if (len
< sizeof(*ip
))
242 ip
= (const struct iphdr
*) data
;
243 if (ip
->version
!= 4)
248 /* TODO: check header checksum in ip->check */
250 frag_off
= be_to_host16(ip
->frag_off
);
251 if (frag_off
& 0x1fff) {
252 wpa_printf(MSG_EXCESSIVE
, "IP fragment reassembly not yet "
257 tot_len
= be_to_host16(ip
->tot_len
);
263 payload
= data
+ 4 * ip
->ihl
;
264 plen
= len
- 4 * ip
->ihl
;
265 if (payload
+ plen
> data
+ len
)
268 switch (ip
->protocol
) {
270 process_udp(wt
, ip
->daddr
, ip
->saddr
, payload
, plen
);
276 void wlantest_process_wired(struct wlantest
*wt
, const u8
*data
, size_t len
)
278 const struct ether_header
*eth
;
281 wpa_hexdump(MSG_EXCESSIVE
, "Process wired frame", data
, len
);
283 if (len
< sizeof(*eth
))
286 eth
= (const struct ether_header
*) data
;
287 ethertype
= be_to_host16(eth
->ether_type
);
291 process_ipv4(wt
, data
+ sizeof(*eth
), len
- sizeof(*eth
));