Home | History | Annotate | Download | only in l2_packet
      1 /*
      2  * WPA Supplicant - Layer2 packet handling with Linux packet sockets
      3  * Copyright (c) 2003-2005, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 #include <sys/ioctl.h>
     17 #include <netpacket/packet.h>
     18 #include <net/if.h>
     19 
     20 #include "common.h"
     21 #include "eloop.h"
     22 #include "l2_packet.h"
     23 
     24 
     25 struct l2_packet_data {
     26 	int fd; /* packet socket for EAPOL frames */
     27 	char ifname[IFNAMSIZ + 1];
     28 	int ifindex;
     29 	u8 own_addr[ETH_ALEN];
     30 	void (*rx_callback)(void *ctx, const u8 *src_addr,
     31 			    const u8 *buf, size_t len);
     32 	void *rx_callback_ctx;
     33 	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
     34 		     * buffers */
     35 };
     36 
     37 
     38 int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
     39 {
     40 	os_memcpy(addr, l2->own_addr, ETH_ALEN);
     41 	return 0;
     42 }
     43 
     44 
     45 int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
     46 		   const u8 *buf, size_t len)
     47 {
     48 	int ret;
     49 	if (l2 == NULL)
     50 		return -1;
     51 	if (l2->l2_hdr) {
     52 		ret = send(l2->fd, buf, len, 0);
     53 		if (ret < 0)
     54 			perror("l2_packet_send - send");
     55 	} else {
     56 		struct sockaddr_ll ll;
     57 		os_memset(&ll, 0, sizeof(ll));
     58 		ll.sll_family = AF_PACKET;
     59 		ll.sll_ifindex = l2->ifindex;
     60 		ll.sll_protocol = htons(proto);
     61 		ll.sll_halen = ETH_ALEN;
     62 		os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
     63 		ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
     64 			     sizeof(ll));
     65 		if (ret < 0)
     66 			perror("l2_packet_send - sendto");
     67 	}
     68 	return ret;
     69 }
     70 
     71 
     72 static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
     73 {
     74 	struct l2_packet_data *l2 = eloop_ctx;
     75 	u8 buf[2300];
     76 	int res;
     77 	struct sockaddr_ll ll;
     78 	socklen_t fromlen;
     79 
     80 	os_memset(&ll, 0, sizeof(ll));
     81 	fromlen = sizeof(ll);
     82 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
     83 		       &fromlen);
     84 	if (res < 0) {
     85 		perror("l2_packet_receive - recvfrom");
     86 		return;
     87 	}
     88 
     89 	l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
     90 }
     91 
     92 
     93 struct l2_packet_data * l2_packet_init(
     94 	const char *ifname, const u8 *own_addr, unsigned short protocol,
     95 	void (*rx_callback)(void *ctx, const u8 *src_addr,
     96 			    const u8 *buf, size_t len),
     97 	void *rx_callback_ctx, int l2_hdr)
     98 {
     99 	struct l2_packet_data *l2;
    100 	struct ifreq ifr;
    101 	struct sockaddr_ll ll;
    102 
    103 	l2 = os_zalloc(sizeof(struct l2_packet_data));
    104 	if (l2 == NULL)
    105 		return NULL;
    106 	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
    107 	l2->rx_callback = rx_callback;
    108 	l2->rx_callback_ctx = rx_callback_ctx;
    109 	l2->l2_hdr = l2_hdr;
    110 
    111 	l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
    112 			htons(protocol));
    113 	if (l2->fd < 0) {
    114 		perror("socket(PF_PACKET)");
    115 		os_free(l2);
    116 		return NULL;
    117 	}
    118 	os_memset(&ifr, 0, sizeof(ifr));
    119 	os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
    120 	if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) {
    121 		perror("ioctl[SIOCGIFINDEX]");
    122 		close(l2->fd);
    123 		os_free(l2);
    124 		return NULL;
    125 	}
    126 	l2->ifindex = ifr.ifr_ifindex;
    127 
    128 	os_memset(&ll, 0, sizeof(ll));
    129 	ll.sll_family = PF_PACKET;
    130 	ll.sll_ifindex = ifr.ifr_ifindex;
    131 	ll.sll_protocol = htons(protocol);
    132 	if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
    133 		perror("bind[PF_PACKET]");
    134 		close(l2->fd);
    135 		os_free(l2);
    136 		return NULL;
    137 	}
    138 
    139 	if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) {
    140 		perror("ioctl[SIOCGIFHWADDR]");
    141 		close(l2->fd);
    142 		os_free(l2);
    143 		return NULL;
    144 	}
    145 	os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
    146 
    147 	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
    148 
    149 	return l2;
    150 }
    151 
    152 
    153 void l2_packet_deinit(struct l2_packet_data *l2)
    154 {
    155 	if (l2 == NULL)
    156 		return;
    157 
    158 	if (l2->fd >= 0) {
    159 		eloop_unregister_read_sock(l2->fd);
    160 		close(l2->fd);
    161 	}
    162 
    163 	os_free(l2);
    164 }
    165 
    166 
    167 int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
    168 {
    169 	int s;
    170 	struct ifreq ifr;
    171 	struct sockaddr_in *saddr;
    172 	size_t res;
    173 
    174 	s = socket(PF_INET, SOCK_DGRAM, 0);
    175 	if (s < 0) {
    176 		perror("socket");
    177 		return -1;
    178 	}
    179 	os_memset(&ifr, 0, sizeof(ifr));
    180 	os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
    181 	if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
    182 		if (errno != EADDRNOTAVAIL)
    183 			perror("ioctl[SIOCGIFADDR]");
    184 		close(s);
    185 		return -1;
    186 	}
    187 	close(s);
    188 	saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in);
    189 	if (saddr->sin_family != AF_INET)
    190 		return -1;
    191 	res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len);
    192 	if (res >= len)
    193 		return -1;
    194 	return 0;
    195 }
    196 
    197 
    198 void l2_packet_notify_auth_start(struct l2_packet_data *l2)
    199 {
    200 }
    201