summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/wireless.c
blob: c9e36304891414ca51ac256791e4dec1b444143f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * Olivier Blin (oblin)
 *
 * Copyright 2005 Mandriva
 *
 * This software may be freely redistributed under the terms of the GNU
 * public license.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/types.h>
#include <linux/if.h>
#include <linux/wireless.h>

#include "automatic.h"
#include "stage1.h"
#include "log.h"
#include "utils.h"
#include "wireless.h"

static int wireless_ioctl(int socket, const char *ifname, int request, struct iwreq *wrq);
static int wireless_set_mode_managed(int socket, const char *ifname);
static int wireless_disable_key(int socket, const char *ifname);
static int wireless_set_restricted_key(int socket, const char *ifname, const char *key);
static int wireless_set_essid(int socket, const char *ifname, const char *essid);

int wireless_open_socket()
{
	return socket(AF_INET, SOCK_DGRAM, 0);
}

int wireless_close_socket(int socket)
{
	return close(socket);
}

static int wireless_ioctl(int socket, const char *ifname, int request, struct iwreq *wrq)
{
	strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
	return ioctl(socket, request, wrq);
}

int wireless_is_aware(int socket, const char *ifname)
{
	struct iwreq wrq;
	return wireless_ioctl(socket, ifname, SIOCGIWNAME, &wrq) == 0;
}

static int wireless_set_mode_managed(int socket, const char *ifname)
{
	struct iwreq wrq;

	wrq.u.mode = IW_MODE_INFRA; /* managed */

	return wireless_ioctl(socket, ifname, SIOCSIWMODE, &wrq) == 0;
}

static int wireless_set_essid(int socket, const char *ifname, const char *essid)
{
	struct iwreq wrq;

	wrq.u.essid.flags = 1;
	wrq.u.essid.pointer = (void *) essid;
	wrq.u.essid.length = strlen(essid) + 1;

	return wireless_ioctl(socket, ifname, SIOCSIWESSID, &wrq) == 0;
}

static int wireless_disable_key(int socket, const char *ifname)
{
	struct iwreq wrq;

	wrq.u.data.flags = IW_ENCODE_DISABLED;
	wrq.u.data.pointer = NULL;
	wrq.u.data.length = 0;

	return wireless_ioctl(socket, ifname, SIOCSIWENCODE, &wrq) == 0;
}

static int wireless_set_restricted_key(int socket, const char *ifname, const char *key)
{
	struct iwreq wrq;
	char real_key[IW_ENCODING_TOKEN_MAX];
	int key_len = 0;
	unsigned int tmp;

	while (sscanf(key + 2*key_len, "%2X", &tmp) == 1)
		real_key[key_len++] = (char) tmp;

	wrq.u.data.flags = IW_ENCODE_RESTRICTED;
	wrq.u.data.pointer = (char *) real_key;
	wrq.u.data.length = key_len;

	return wireless_ioctl(socket, ifname, SIOCSIWENCODE, &wrq) == 0;
}

enum return_type configure_wireless(const char *ifname)
{
	enum return_type results;
	char * questions[] = { "ESSID", "WEP key", NULL };
	char * questions_auto[] = { "essid", "wep_key" };
	static char ** answers = NULL;
	int wsock = wireless_open_socket();

	if (!wireless_is_aware(wsock, ifname)) {
		log_message("interface %s doesn't support wireless", ifname);
		wireless_close_socket(wsock);
		return RETURN_OK;
	}

	results = ask_from_entries_auto("Please enter your wireless settings. "
                                        "The ESSID is your wireless network identifier. "
                                        "The WEP key must be entered in hexadecimal, without any separator.",
					questions, &answers, 32, questions_auto, NULL);
	if (results != RETURN_OK) {
		wireless_close_socket(wsock);
		return RETURN_BACK;
	}

	if (!wireless_set_mode_managed(wsock, ifname)) {
		stg1_error_message("unable to set mode Managed on device \"%s\": %s", ifname, strerror(errno));
		wireless_close_socket(wsock);
		return RETURN_ERROR;
	}

	if (answers[1] && !streq(answers[1], "")) {
		log_message("setting WEP key \"%s\" on device \"%s\"", answers[1], ifname);
		if (!wireless_set_restricted_key(wsock, ifname, answers[1])) {
			stg1_error_message("unable to set WEP key \"%s\" on device \"%s\": %s", answers[1], ifname, strerror(errno));
			return RETURN_ERROR;
		}
	} else {
		log_message("disabling WEP key on device \"%s\"", ifname);
		if (!wireless_disable_key(wsock, ifname)) {
			stg1_error_message("unable to disable WEP key on device \"%s\": %s", ifname, strerror(errno));
			return RETURN_ERROR;
		}
	}

        /* most devices perform discovery when ESSID is set, it needs to be last */
	log_message("setting ESSID \"%s\" on device \"%s\"", answers[0], ifname);
	if (!wireless_set_essid(wsock, ifname, answers[0])) {
		stg1_error_message("unable to set ESSID \"%s\" on device \"%s\": %s", answers[0], ifname, strerror(errno));
		return RETURN_ERROR;
	}

	wireless_close_socket(wsock);
	return RETURN_OK;
}