1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	/*
3    	 * This library is free software; you can redistribute it and/or
4    	 * modify it under the terms of the GNU Lesser General Public
5    	 * License as published by the Free Software Foundation; either
6    	 * version 2 of the License, or (at your option) any later version.
7    	 *
8    	 * This library is distributed in the hope that it will be useful,
9    	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   	 * Lesser General Public License for more details.
12   	 *
13   	 * You should have received a copy of the GNU Lesser General Public
14   	 * License along with this library; if not, write to the
15   	 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16   	 * Boston, MA 02110-1301 USA.
17   	 *
18   	 * (C) Copyright 2011 Red Hat, Inc.
19   	 */
20   	
21   	#include <config.h>
22   	#include <string.h>
23   	#include <stdlib.h>
24   	
25   	#include "nm-wifi-ap-utils.h"
26   	
27   	static gboolean
28   	verify_no_wep (NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error)
29   	{
30   		if (   nm_setting_wireless_security_get_wep_key (s_wsec, 0)
31   		    || nm_setting_wireless_security_get_wep_key (s_wsec, 1)
32   		    || nm_setting_wireless_security_get_wep_key (s_wsec, 2)
33   		    || nm_setting_wireless_security_get_wep_key (s_wsec, 3)
34   		    || nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec)
35   		    || nm_setting_wireless_security_get_wep_key_type (s_wsec)) {
36   			/* Dynamic WEP cannot have any WEP keys set */
37   			g_set_error (error,
38   			             NM_SETTING_WIRELESS_SECURITY_ERROR,
39   			             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
40   			             "%s is incompatible with static WEP keys", tag);
41   			return FALSE;
42   		}
43   	
44   		return TRUE;
45   	}
46   	
47   	static gboolean
48   	verify_leap (NMSettingWirelessSecurity *s_wsec,
49   	             NMSetting8021x *s_8021x,
50   	             gboolean adhoc,
51   	             GError **error)
52   	{
53   		const char *key_mgmt, *auth_alg, *leap_username;
54   	
55   		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
56   		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
57   		leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
58   	
59   		/* One (or both) of two things indicates we want LEAP:
60   		 * 1) auth_alg == 'leap'
61   		 * 2) valid leap_username
62   	     *
63   	     * LEAP always requires a LEAP username.
64   		 */
65   	
66   		if (auth_alg) {
67   			if (!strcmp (auth_alg, "leap")) {
68   				/* LEAP authentication requires at least a LEAP username */
69   				if (!leap_username) {
70   					g_set_error_literal (error,
71   					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
72   					                     NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME,
73   					                     "LEAP requires a LEAP username");
74   					return FALSE;
75   				}
76   			} else if (leap_username) {
77   				/* Leap username requires 'leap' auth */
78   				g_set_error_literal (error,
79   				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
80   				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
81   				                     "LEAP requires 'leap' authentication");
82   				return FALSE;
83   			}
84   		}
85   	
86   		if (leap_username) {
87   			if (key_mgmt && strcmp (key_mgmt, "ieee8021x")) {
88   				/* LEAP requires ieee8021x key management */
89   				g_set_error_literal (error,
90   				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
91   				                     NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_802_1X,
92   				                     "LEAP requires IEEE 802.1x key management");
93   				return FALSE;
94   			}
95   		}
96   	
97   		/* At this point if auth_alg is set it must be 'leap', and if key_mgmt
98   		 * is set it must be 'ieee8021x'.
99   		 */
100  		if (leap_username) {
101  			if (auth_alg)
102  				g_assert (strcmp (auth_alg, "leap") == 0);
103  			if (key_mgmt)
104  				g_assert (strcmp (key_mgmt, "ieee8021x") == 0);
105  	
106  			if (adhoc) {
107  				g_set_error_literal (error,
108  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
109  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
110  				                     "LEAP incompatible with Ad-Hoc mode");
111  				return FALSE;
112  			}
113  	
114  			if (!verify_no_wep (s_wsec, "LEAP", error))
115  				return FALSE;
116  	
117  			if (s_8021x) {
118  				g_set_error_literal (error,
119  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
120  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME,
121  				                     "LEAP incompatible with 802.1x setting");
122  				return FALSE;
123  			}
124  		}
125  	
126  		return TRUE;
127  	}
128  	
129  	static gboolean
130  	verify_no_wpa (NMSettingWirelessSecurity *s_wsec,
131  	               const char *tag,
132  	               GError **error)
133  	{
134  		const char *key_mgmt;
135  		int n, i;
136  	
137  		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
138  		if (key_mgmt && !strncmp (key_mgmt, "wpa", 3)) {
139  			g_set_error (error,
140  			             NM_SETTING_WIRELESS_SECURITY_ERROR,
141  			             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
142  			             "%s incompatible with any WPA key management", tag);
143  			return FALSE;
144  		}
145  	
146  		if (nm_setting_wireless_security_get_num_protos (s_wsec)) {
147  			g_set_error (error,
148  			             NM_SETTING_WIRELESS_SECURITY_ERROR,
149  			             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
150  			             "%s incompatible with any 'proto' setting", tag);
151  			return FALSE;
152  		}
153  	
154  		n = nm_setting_wireless_security_get_num_pairwise (s_wsec);
155  		for (i = 0; i < n; i++) {
156  			const char *pw;
157  	
158  			pw = nm_setting_wireless_security_get_pairwise (s_wsec, i);
159  			if (!strcmp (pw, "tkip") || !strcmp (pw, "ccmp")) {
160  				g_set_error (error,
161  				             NM_SETTING_WIRELESS_SECURITY_ERROR,
162  				             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
163  				             "%s is incompatible with WPA pairwise ciphers", tag);
164  				return FALSE;
165  			}
166  		}
167  	
168  		n = nm_setting_wireless_security_get_num_groups (s_wsec);
169  		for (i = 0; i < n; i++) {
170  			const char *gr;
171  	
172  			gr = nm_setting_wireless_security_get_group (s_wsec, i);
173  			if (strcmp (gr, "wep40") && strcmp (gr, "wep104")) {
174  				g_set_error (error,
175  				             NM_SETTING_WIRELESS_SECURITY_ERROR,
176  				             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
177  				             "%s is incompatible with WPA group ciphers", tag);
178  				return FALSE;
179  			}
180  		}
181  	
182  		if (nm_setting_wireless_security_get_psk (s_wsec)) {
183  			g_set_error (error,
184  			             NM_SETTING_WIRELESS_SECURITY_ERROR,
185  			             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
186  			             "%s is incompatible with a WPA Pre-Shared Key", tag);
187  			return FALSE;
188  		}
189  	
190  		return TRUE;
191  	}
192  	
193  	static gboolean
194  	verify_dynamic_wep (NMSettingWirelessSecurity *s_wsec,
195  	                    NMSetting8021x *s_8021x,
196  	                    gboolean adhoc,
197  	                    GError **error)
198  	{
199  		const char *key_mgmt, *auth_alg, *leap_username;
200  	
201  		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
202  		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
203  		leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
204  	
205  		g_return_val_if_fail (leap_username == NULL, TRUE);
206  	
207  		if (key_mgmt) {
208  			if (!strcmp (key_mgmt, "ieee8021x")) {
209  				if (!s_8021x) {
210  					/* 802.1x key management requires an 802.1x setting */
211  					g_set_error_literal (error,
212  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
213  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
214  					                     "Dynamic WEP requires an 802.1x setting");
215  					return FALSE;
216  				}
217  	
218  				if (auth_alg && strcmp (auth_alg, "open")) {
219  					/* 802.1x key management must use "open" authentication */
220  					g_set_error_literal (error,
221  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
222  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
223  					                     "Dynamic WEP requires 'open' authentication");
224  					return FALSE;
225  				}
226  	
227  				/* Dynamic WEP incompatible with anything static WEP related */
228  				if (!verify_no_wep (s_wsec, "Dynamic WEP", error))
229  					return FALSE;
230  			} else if (!strcmp (key_mgmt, "none")) {
231  				if (s_8021x) {
232  					/* 802.1x setting requires 802.1x key management */
233  					g_set_error_literal (error,
234  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
235  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
236  					                     "Dynamic WEP requires 'ieee8021x' key management");
237  					return FALSE;
238  				}
239  			}
240  		} else if (s_8021x) {
241  			/* 802.1x setting incompatible with anything but 'open' auth */
242  			if (auth_alg && strcmp (auth_alg, "open")) {
243  				/* 802.1x key management must use "open" authentication */
244  				g_set_error_literal (error,
245  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
246  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
247  				                     "Dynamic WEP requires 'open' authentication");
248  				return FALSE;
249  			}
250  	
251  			/* Dynamic WEP incompatible with anything static WEP related */
252  			if (!verify_no_wep (s_wsec, "Dynamic WEP", error))
253  				return FALSE;
254  		}
255  	
256  		return TRUE;
257  	}
258  	
259  	static gboolean
260  	verify_wpa_psk (NMSettingWirelessSecurity *s_wsec,
261  	                NMSetting8021x *s_8021x,
262  	                gboolean adhoc,
263  	                guint32 wpa_flags,
264  	                guint32 rsn_flags,
265  	                GError **error)
266  	{
267  		const char *key_mgmt, *auth_alg, *tmp;
268  		int n;
269  	
270  		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
271  		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
272  	
(1) Event cond_true: Condition "key_mgmt", taking true branch
273  		if (key_mgmt) {
(2) Event cond_true: Condition "!__coverity_strcmp(key_mgmt, "wpa-psk")", taking true branch
274  			if (!strcmp (key_mgmt, "wpa-psk") || !strcmp (key_mgmt, "wpa-none")) {
(3) Event cond_false: Condition "s_8021x", taking false branch
275  				if (s_8021x) {
276  					g_set_error_literal (error,
277  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
278  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
279  					                     "WPA-PSK incompatible with 802.1x");
280  					return FALSE;
(4) Event if_end: End of if statement
281  				}
282  	
(5) Event cond_true: Condition "auth_alg", taking true branch
(6) Event cond_false: Condition "__coverity_strcmp(auth_alg, "open")", taking false branch
283  				if (auth_alg && strcmp (auth_alg, "open")) {
284  					/* WPA must use "open" authentication */
285  					g_set_error_literal (error,
286  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
287  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
288  					                     "WPA-PSK requires 'open' authentication");
289  					return FALSE;
(7) Event if_end: End of if statement
290  				}
291  			}
292  	
(8) Event cond_true: Condition "!__coverity_strcmp(key_mgmt, "wpa-none")", taking true branch
293  			if (!strcmp (key_mgmt, "wpa-none")) {
(9) Event cond_false: Condition "!adhoc", taking false branch
294  				if (!adhoc) {
295  					g_set_error_literal (error,
296  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
297  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
298  					                     "WPA Ad-Hoc requires an Ad-Hoc mode AP");
299  					return FALSE;
(10) Event if_end: End of if statement
300  				}
301  	
302  				/* Ad-Hoc WPA requires 'wpa' proto, 'none' pairwise, and 'tkip' group */
303  				n = nm_setting_wireless_security_get_num_protos (s_wsec);
(11) Event cond_true: Condition "n > 0", taking true branch
304  				tmp = (n > 0) ? nm_setting_wireless_security_get_proto (s_wsec, 0) : NULL;
(12) Event cond_false: Condition "n > 1", taking false branch
(13) Event cond_false: Condition "__coverity_strcmp(tmp, "wpa")", taking false branch
305  				if (n > 1 || strcmp (tmp, "wpa")) {
306  					g_set_error_literal (error,
307  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
308  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
309  					                     "WPA Ad-Hoc requires 'wpa' proto");
310  					return FALSE;
(14) Event if_end: End of if statement
311  				}
312  	
313  				n = nm_setting_wireless_security_get_num_pairwise (s_wsec);
(15) Event cond_true: Condition "n > 0", taking true branch
314  				tmp = (n > 0) ? nm_setting_wireless_security_get_pairwise (s_wsec, 0) : NULL;
(16) Event cond_false: Condition "n > 1", taking false branch
(17) Event cond_false: Condition "__coverity_strcmp(tmp, "none")", taking false branch
315  				if (n > 1 || strcmp (tmp, "none")) {
316  					g_set_error_literal (error,
317  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
318  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
319  					                     "WPA Ad-Hoc requires 'none' pairwise cipher");
320  					return FALSE;
(18) Event if_end: End of if statement
321  				}
322  	
323  				n = nm_setting_wireless_security_get_num_groups (s_wsec);
(19) Event cond_false: Condition "n > 0", taking false branch
(20) Event assign_zero: Assigning: "tmp" = "NULL".
Also see events: [var_deref_model]
324  				tmp = (n > 0) ? nm_setting_wireless_security_get_group (s_wsec, 0) : NULL;
(21) Event cond_false: Condition "n > 1", taking false branch
(22) Event var_deref_model: Passing null pointer "tmp" to function "__coverity_strcmp(char const *, char const *)", which dereferences it.
Also see events: [assign_zero]
325  				if (n > 1 || strcmp (tmp, "tkip")) {
326  					g_set_error_literal (error,
327  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
328  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
329  					                     "WPA Ad-Hoc requires 'tkip' group cipher");
330  					return FALSE;
331  				}
332  			}
333  	
334  			if (!strcmp (key_mgmt, "wpa-psk")) {
335  				/* Make sure the AP's capabilities support WPA-PSK */
336  				if (   !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
337  				    && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
338  					g_set_error_literal (error,
339  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
340  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
341  					                     "AP does not support PSK but setting requires it");
342  					return FALSE;
343  				}
344  			}
345  		}
346  	
347  		return TRUE;
348  	}
349  	
350  	static gboolean
351  	verify_wpa_eap (NMSettingWirelessSecurity *s_wsec,
352  	                NMSetting8021x *s_8021x,
353  	                guint32 wpa_flags,
354  	                guint32 rsn_flags,
355  	                GError **error)
356  	{
357  		const char *key_mgmt, *auth_alg;
358  		gboolean is_wpa_eap = FALSE;
359  	
360  		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
361  		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
362  	
363  		if (key_mgmt) {
364  			if (!strcmp (key_mgmt, "wpa-eap")) {
365  				if (!s_8021x) {
366  					g_set_error_literal (error,
367  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
368  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
369  					                     "WPA-EAP requires an 802.1x setting");
370  					return FALSE;
371  				}
372  	
373  				if (auth_alg && strcmp (auth_alg, "open")) {
374  					/* WPA must use "open" authentication */
375  					g_set_error_literal (error,
376  					                     NM_SETTING_WIRELESS_SECURITY_ERROR,
377  					                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
378  					                     "WPA-EAP requires 'open' authentication");
379  					return FALSE;
380  				}
381  	
382  				is_wpa_eap = TRUE;
383  			} else if (s_8021x) {
384  				g_set_error_literal (error,
385  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
386  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
387  				                     "Setting requires 802.1x but does not use 'wpa-eap' key management");
388  				return FALSE;
389  			}
390  		}
391  	
392  		if (is_wpa_eap || s_8021x) {
393  			/* Make sure the AP's capabilities support WPA-EAP */
394  			if (   !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
395  			    && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
396  				g_set_error_literal (error,
397  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
398  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
399  				                     "AP does not support 802.1x but setting requires it");
400  				return FALSE;
401  			}
402  		}
403  	
404  		return TRUE;
405  	}
406  	
407  	static gboolean
408  	verify_adhoc (NMSettingWirelessSecurity *s_wsec,
409  	              NMSetting8021x *s_8021x,
410  	              gboolean adhoc,
411  	              GError **error)
412  	{
413  		const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL;
414  	
415  		if (s_wsec) {
416  			key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
417  			auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
418  			leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
419  		}
420  	
421  		if (adhoc) {
422  			if (key_mgmt && strcmp (key_mgmt, "wpa-none") && strcmp (key_mgmt, "none")) {
423  				g_set_error_literal (error,
424  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
425  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
426  				                     "AP mode is Ad-Hoc but setting requires Infrastructure security");
427  				return FALSE;
428  			}
429  	
430  			if (s_8021x) {
431  				g_set_error_literal (error,
432  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
433  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
434  				                     "Ad-Hoc mode incompatible with 802.1x security");
435  				return FALSE;
436  			}
437  	
438  			if (leap_username) {
439  				g_set_error_literal (error,
440  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
441  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
442  				                     "Ad-Hoc mode incompatible with LEAP security");
443  				return FALSE;
444  			}
445  	
446  			if (auth_alg && strcmp (auth_alg, "open")) {
447  				g_set_error_literal (error,
448  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
449  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
450  				                     "Ad-Hoc mode requires 'open' authentication");
451  				return FALSE;
452  			}
453  		} else {
454  			if (key_mgmt && !strcmp (key_mgmt, "wpa-none")) {
455  				g_set_error_literal (error,
456  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
457  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
458  				                     "AP mode is Infrastructure but setting requires Ad-Hoc security");
459  				return FALSE;
460  			}
461  		}
462  	
463  		return TRUE;
464  	}
465  	
466  	gboolean
467  	nm_ap_utils_complete_connection (const GByteArray *ap_ssid,
468  	                                 const guint8 ap_bssid[ETH_ALEN],
469  	                                 NM80211Mode ap_mode,
470  	                                 guint32 ap_flags,
471  	                                 guint32 ap_wpa_flags,
472  	                                 guint32 ap_rsn_flags,
473  	                                 NMConnection *connection,
474  	                                 gboolean lock_bssid,
475  	                                 GError **error)
476  	{
477  		NMSettingWireless *s_wifi;
478  		NMSettingWirelessSecurity *s_wsec;
479  		NMSetting8021x *s_8021x;
480  		const GByteArray *ssid;
481  		const char *mode, *key_mgmt, *auth_alg, *leap_username;
482  		gboolean adhoc = FALSE;
483  	
484  		s_wifi = nm_connection_get_setting_wireless (connection);
485  		g_assert (s_wifi);
486  		s_wsec = nm_connection_get_setting_wireless_security (connection);
487  		s_8021x = nm_connection_get_setting_802_1x (connection);
488  	
489  		/* Fill in missing SSID */
490  		ssid = nm_setting_wireless_get_ssid (s_wifi);
491  		if (!ssid)
492  			g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid, NULL);
493  		else if (   ssid->len != ap_ssid->len
494  		         || memcmp (ssid->data, ap_ssid->data, ssid->len)) {
495  			g_set_error_literal (error,
496  			                     NM_SETTING_WIRELESS_ERROR,
497  			                     NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
498  			                     "Setting SSID did not match AP SSID");
499  			return FALSE;
500  		}
501  	
502  		if (lock_bssid && !nm_setting_wireless_get_bssid (s_wifi)) {
503  			GByteArray *bssid;
504  	
505  			bssid = g_byte_array_sized_new (ETH_ALEN);
506  			g_byte_array_append (bssid, ap_bssid, ETH_ALEN);
507  			g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL);
508  			g_byte_array_free (bssid, TRUE);
509  		}
510  	
511  		/* And mode */
512  		mode = nm_setting_wireless_get_mode (s_wifi);
513  		if (mode) {
514  			gboolean valid = FALSE;
515  	
516  			/* Make sure the supplied mode matches the AP's */
517  			if (   !strcmp (mode, NM_SETTING_WIRELESS_MODE_INFRA)
518  			    || !strcmp (mode, NM_SETTING_WIRELESS_MODE_AP)) {
519  				if (ap_mode == NM_802_11_MODE_INFRA)
520  					valid = TRUE;
521  			} else if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
522  				if (ap_mode == NM_802_11_MODE_ADHOC)
523  					valid = TRUE;
524  				adhoc = TRUE;
525  			}
526  	
527  			if (valid == FALSE) {
528  				g_set_error (error,
529  				             NM_SETTING_WIRELESS_ERROR,
530  				             NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
531  				             NM_SETTING_WIRELESS_MODE);
532  				return FALSE;
533  			}
534  		} else {
535  			mode = NM_SETTING_WIRELESS_MODE_INFRA;
536  			if (ap_mode == NM_802_11_MODE_ADHOC) {
537  				mode = NM_SETTING_WIRELESS_MODE_ADHOC;
538  				adhoc = TRUE;
539  			}
540  			g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, mode, NULL);
541  		}
542  	
543  		/* Security */
544  	
545  		/* Open */
546  		if (   !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
547  		    && (ap_wpa_flags == NM_802_11_AP_SEC_NONE)
548  		    && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) {
549  			/* Make sure the connection doesn't specify security */
550  			if (s_wsec || s_8021x) {
551  				g_set_error_literal (error,
552  				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
553  				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
554  				                     "AP is unencrypted but setting specifies security");
555  				return FALSE;
556  			}
557  			return TRUE;
558  		}
559  	
560  		/* Everything else requires security */
561  		if (!s_wsec) {
562  			s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
563  			nm_connection_add_setting (connection, NM_SETTING (s_wsec));
564  		}
565  	
566  		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
567  		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
568  		leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
569  	
570  		/* Ad-Hoc checks */
571  		if (!verify_adhoc (s_wsec, s_8021x, adhoc, error))
572  			return FALSE;
573  	
574  		/* Static WEP, Dynamic WEP, or LEAP */
575  		if (   (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
576  		    && (ap_wpa_flags == NM_802_11_AP_SEC_NONE)
577  		    && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) {
578  			const char *tag = "WEP";
579  			gboolean is_dynamic_wep = FALSE;
580  	
581  			if (!verify_leap (s_wsec, s_8021x, adhoc, error))
582  				return FALSE;
583  	
584  			if (leap_username) {
585  				tag = "LEAP";
586  			} else {
587  				/* Static or Dynamic WEP */
588  				if (!verify_dynamic_wep (s_wsec, s_8021x, adhoc, error))
589  					return FALSE;
590  	
591  				if (s_8021x || (key_mgmt && !strcmp (key_mgmt, "ieee8021x"))) {
592  					is_dynamic_wep = TRUE;
593  					tag = "Dynamic WEP";
594  				}
595  			}
596  	
597  			/* Nothing WPA-related can be set */
598  			if (!verify_no_wpa (s_wsec, tag, error))
599  				return FALSE;
600  	
601  			if (leap_username) {
602  				/* LEAP */
603  				g_object_set (s_wsec,
604  				              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
605  				              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
606  				              NULL);
607  			} else if (is_dynamic_wep) {
608  				/* Dynamic WEP */
609  				g_object_set (s_wsec,
610  				              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
611  				              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
612  				              NULL);
613  	
614  				if (s_8021x) {
615  					/* Dynamic WEP requires a valid 802.1x setting since we can't
616  					 * autocomplete 802.1x.
617  					 */
618  					if (!nm_setting_verify (NM_SETTING (s_8021x), NULL, error))
619  						return FALSE;
620  				}
621  			} else {
622  				/* Static WEP */
623  				g_object_set (s_wsec,
624  				              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
625  				              NULL);
626  			}
627  	
628  			return TRUE;
629  		}
630  	
631  		/* WPA/RSN */
632  		g_assert (ap_wpa_flags || ap_rsn_flags);
633  	
634  		/* Ensure key management is valid for WPA */
635  		if ((key_mgmt && !strcmp (key_mgmt, "ieee8021x")) || leap_username) {
636  			g_set_error_literal (error,
637  			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
638  			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
639  			                     "WPA incompatible with non-EAP (original) LEAP or Dynamic WEP");
640  			return FALSE;
641  		}
642  	
643  		/* 'shared' auth incompatible with any type of WPA */
644  		if (auth_alg && strcmp (auth_alg, "open")) {
645  			g_set_error_literal (error,
646  			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
647  			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
648  			                     "WPA incompatible with Shared Key authentication");
649  			return FALSE;
650  		}
651  	
652  		if (!verify_no_wep (s_wsec, "WPA", error))
653  			return FALSE;
654  	
655  		if (!verify_wpa_psk (s_wsec, s_8021x, adhoc, ap_wpa_flags, ap_rsn_flags, error))
656  			return FALSE;
657  	
658  		if (!adhoc && !verify_wpa_eap (s_wsec, s_8021x, ap_wpa_flags, ap_rsn_flags, error))
659  			return FALSE;
660  	
661  		if (adhoc) {
662  			g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
663  			/* Ad-Hoc does not support RSN/WPA2 */
664  			nm_setting_wireless_security_add_proto (s_wsec, "wpa");
665  			nm_setting_wireless_security_add_pairwise (s_wsec, "none");
666  			nm_setting_wireless_security_add_group (s_wsec, "tkip");
667  		} else if (s_8021x) {
668  			g_object_set (s_wsec,
669  			              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
670  			              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
671  			              NULL);
672  			/* Leave proto/pairwise/group as client set them; if they are unset the
673  			 * supplicant will figure out the best combination at connect time.
674  			 */
675  	
676  			/* 802.1x also requires the client to completely fill in the 8021x
677  			 * setting.  Since there's so much configuration required for it, there's
678  			 * no way it can be automatically completed.
679  			 */
680  		} else if (   (key_mgmt && !strcmp (key_mgmt, "wpa-psk"))
681  		           || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
682  		           || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
683  			g_object_set (s_wsec,
684  			              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
685  			              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
686  			              NULL);
687  			/* Leave proto/pairwise/group as client set them; if they are unset the
688  			 * supplicant will figure out the best combination at connect time.
689  			 */
690  		} else {
691  			g_set_error_literal (error,
692  			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
693  			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
694  			                     "Failed to determine AP security information");
695  			return FALSE;
696  		}
697  	
698  		return TRUE;
699  	}
700  	
701  	guint32
702  	nm_ap_utils_level_to_quality (gint val)
703  	{
704  		if (val < 0) {
705  			/* Assume dBm already; rough conversion: best = -40, worst = -100 */
706  			val = abs (CLAMP (val, -100, -40) + 40);  /* normalize to 0 */
707  			val = 100 - (int) ((100.0 * (double) val) / 60.0);
708  		} else if (val > 110 && val < 256) {
709  			/* assume old-style WEXT 8-bit unsigned signal level */
710  			val -= 256;  /* subtract 256 to convert to dBm */
711  			val = abs (CLAMP (val, -100, -40) + 40);  /* normalize to 0 */
712  			val = 100 - (int) ((100.0 * (double) val) / 60.0);
713  		} else {
714  			/* Assume signal is a "quality" percentage */
715  			val = CLAMP (val, 0, 100);
716  		}
717  		g_assert (val >= 0);
718  	
719  		return (guint32) val;
720  	}
721  	
722