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
)
92 struct wlantest_pmk
*p
;
94 p
= os_zalloc(sizeof(*p
));
97 os_memcpy(p
->pmk
, pmk
, 32);
98 dl_list_add(&wt
->pmk
, &p
->list
);
99 wpa_hexdump(MSG_INFO
, "Add PMK", pmk
, 32);
103 static void process_radius_access_accept(struct wlantest
*wt
, u32 dst
, u32 src
,
104 const u8
*data
, size_t len
)
106 struct radius_msg
*msg
;
107 struct wlantest_radius
*r
;
108 struct radius_ms_mppe_keys
*keys
;
109 struct wlantest_radius_secret
*s
;
111 r
= radius_get(wt
, src
, dst
);
112 if (r
== NULL
|| r
->last_req
== NULL
) {
113 wpa_printf(MSG_DEBUG
, "No RADIUS Access-Challenge found for "
114 "decrypting Access-Accept keys");
118 msg
= radius_msg_parse(data
, len
);
120 wpa_printf(MSG_DEBUG
, "Failed to parse RADIUS Access-Accept");
124 dl_list_for_each(s
, &wt
->secret
, struct wlantest_radius_secret
, list
) {
126 keys
= radius_msg_get_ms_keys(msg
, r
->last_req
,
128 os_strlen(s
->secret
));
129 if (keys
&& keys
->send
&& keys
->recv
) {
131 wpa_hexdump_key(MSG_DEBUG
, "MS-MPPE-Send-Key",
132 keys
->send
, keys
->send_len
);
133 wpa_hexdump_key(MSG_DEBUG
, "MS-MPPE-Recv-Key",
134 keys
->recv
, keys
->recv_len
);
135 os_memcpy(pmk
, keys
->recv
,
136 keys
->recv_len
> 32 ? 32 : keys
->recv_len
);
137 if (keys
->recv_len
< 32) {
138 os_memcpy(pmk
+ keys
->recv_len
,
140 keys
->recv_len
+ keys
->send_len
> 32
141 ? 32 : 32 - keys
->recv_len
);
143 wlantest_add_pmk(wt
, pmk
);
157 radius_msg_free(msg
);
161 static void process_radius(struct wlantest
*wt
, u32 dst
, u16 dport
, u32 src
,
162 u16 sport
, const u8
*data
, size_t len
)
166 const struct radius_hdr
*hdr
;
169 if (len
< sizeof(*hdr
))
171 hdr
= (const struct radius_hdr
*) data
;
172 rlen
= be_to_host16(hdr
->length
);
179 snprintf(buf
, sizeof(buf
), "%s", inet_ntoa(addr
));
182 wpa_printf(MSG_DEBUG
, "RADIUS %s:%u -> %s:%u id=%u %s",
183 inet_ntoa(addr
), sport
, buf
, dport
, hdr
->identifier
,
184 radius_code_string(hdr
->code
));
187 case RADIUS_CODE_ACCESS_REQUEST
:
188 process_radius_access_request(wt
, dst
, src
, data
, len
);
190 case RADIUS_CODE_ACCESS_ACCEPT
:
191 process_radius_access_accept(wt
, dst
, src
, data
, len
);
197 static void process_udp(struct wlantest
*wt
, u32 dst
, u32 src
,
198 const u8
*data
, size_t len
)
200 const struct udphdr
*udp
;
201 u16 sport
, dport
, ulen
;
205 if (len
< sizeof(*udp
))
207 udp
= (const struct udphdr
*) data
;
208 /* TODO: check UDP checksum */
209 sport
= be_to_host16(udp
->source
);
210 dport
= be_to_host16(udp
->dest
);
211 ulen
= be_to_host16(udp
->len
);
218 payload
= (const u8
*) (udp
+ 1);
219 plen
= len
- sizeof(*udp
);
221 if (sport
== 1812 || dport
== 1812)
222 process_radius(wt
, dst
, dport
, src
, sport
, payload
, plen
);
226 static void process_ipv4(struct wlantest
*wt
, const u8
*data
, size_t len
)
228 const struct iphdr
*ip
;
231 u16 frag_off
, tot_len
;
233 if (len
< sizeof(*ip
))
236 ip
= (const struct iphdr
*) data
;
237 if (ip
->version
!= 4)
242 /* TODO: check header checksum in ip->check */
244 frag_off
= be_to_host16(ip
->frag_off
);
245 if (frag_off
& 0x1fff) {
246 wpa_printf(MSG_EXCESSIVE
, "IP fragment reassembly not yet "
251 tot_len
= be_to_host16(ip
->tot_len
);
257 payload
= data
+ 4 * ip
->ihl
;
258 plen
= len
- 4 * ip
->ihl
;
259 if (payload
+ plen
> data
+ len
)
262 switch (ip
->protocol
) {
264 process_udp(wt
, ip
->daddr
, ip
->saddr
, payload
, plen
);
270 void wlantest_process_wired(struct wlantest
*wt
, const u8
*data
, size_t len
)
272 const struct ether_header
*eth
;
275 wpa_hexdump(MSG_EXCESSIVE
, "Process wired frame", data
, len
);
277 if (len
< sizeof(*eth
))
280 eth
= (const struct ether_header
*) data
;
281 ethertype
= be_to_host16(eth
->ether_type
);
285 process_ipv4(wt
, data
+ sizeof(*eth
), len
- sizeof(*eth
));