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 wpa_printf(MSG_ERROR, "l2_packet_send - send: %s", 55 strerror(errno)); 56 } else { 57 struct sockaddr_ll ll; 58 os_memset(&ll, 0, sizeof(ll)); 59 ll.sll_family = AF_PACKET; 60 ll.sll_ifindex = l2->ifindex; 61 ll.sll_protocol = htons(proto); 62 ll.sll_halen = ETH_ALEN; 63 os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN); 64 ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll, 65 sizeof(ll)); 66 if (ret < 0) { 67 wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s", 68 strerror(errno)); 69 } 70 } 71 return ret; 72 } 73 74 75 static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) 76 { 77 struct l2_packet_data *l2 = eloop_ctx; 78 u8 buf[2300]; 79 int res; 80 struct sockaddr_ll ll; 81 socklen_t fromlen; 82 83 os_memset(&ll, 0, sizeof(ll)); 84 fromlen = sizeof(ll); 85 res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, 86 &fromlen); 87 if (res < 0) { 88 wpa_printf(MSG_DEBUG, "l2_packet_receive - recvfrom: %s", 89 strerror(errno)); 90 return; 91 } 92 93 l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); 94 } 95 96 97 struct l2_packet_data * l2_packet_init( 98 const char *ifname, const u8 *own_addr, unsigned short protocol, 99 void (*rx_callback)(void *ctx, const u8 *src_addr, 100 const u8 *buf, size_t len), 101 void *rx_callback_ctx, int l2_hdr) 102 { 103 struct l2_packet_data *l2; 104 struct ifreq ifr; 105 struct sockaddr_ll ll; 106 107 l2 = os_zalloc(sizeof(struct l2_packet_data)); 108 if (l2 == NULL) 109 return NULL; 110 os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); 111 l2->rx_callback = rx_callback; 112 l2->rx_callback_ctx = rx_callback_ctx; 113 l2->l2_hdr = l2_hdr; 114 115 l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, 116 htons(protocol)); 117 if (l2->fd < 0) { 118 wpa_printf(MSG_ERROR, "%s: socket(PF_PACKET): %s", 119 __func__, strerror(errno)); 120 os_free(l2); 121 return NULL; 122 } 123 os_memset(&ifr, 0, sizeof(ifr)); 124 os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); 125 if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) { 126 wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFINDEX]: %s", 127 __func__, strerror(errno)); 128 close(l2->fd); 129 os_free(l2); 130 return NULL; 131 } 132 l2->ifindex = ifr.ifr_ifindex; 133 134 os_memset(&ll, 0, sizeof(ll)); 135 ll.sll_family = PF_PACKET; 136 ll.sll_ifindex = ifr.ifr_ifindex; 137 ll.sll_protocol = htons(protocol); 138 if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) { 139 wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s", 140 __func__, strerror(errno)); 141 close(l2->fd); 142 os_free(l2); 143 return NULL; 144 } 145 146 if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) { 147 wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFHWADDR]: %s", 148 __func__, strerror(errno)); 149 close(l2->fd); 150 os_free(l2); 151 return NULL; 152 } 153 os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 154 155 eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); 156 157 return l2; 158 } 159 160 161 void l2_packet_deinit(struct l2_packet_data *l2) 162 { 163 if (l2 == NULL) 164 return; 165 166 if (l2->fd >= 0) { 167 eloop_unregister_read_sock(l2->fd); 168 close(l2->fd); 169 } 170 171 os_free(l2); 172 } 173 174 175 int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) 176 { 177 int s; 178 struct ifreq ifr; 179 struct sockaddr_in *saddr; 180 size_t res; 181 182 s = socket(PF_INET, SOCK_DGRAM, 0); 183 if (s < 0) { 184 wpa_printf(MSG_ERROR, "%s: socket: %s", 185 __func__, strerror(errno)); 186 return -1; 187 } 188 os_memset(&ifr, 0, sizeof(ifr)); 189 os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); 190 if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { 191 if (errno != EADDRNOTAVAIL) 192 wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFADDR]: %s", 193 __func__, strerror(errno)); 194 close(s); 195 return -1; 196 } 197 close(s); 198 saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in); 199 if (saddr->sin_family != AF_INET) 200 return -1; 201 res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len); 202 if (res >= len) 203 return -1; 204 return 0; 205 } 206 207 208 void l2_packet_notify_auth_start(struct l2_packet_data *l2) 209 { 210 } 211