a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Use is subject to license terms.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Sun elects to license this software under the BSD license.
a399b7655a1d835aa8606c2b29e4e777baac8635zf * See README for more details.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf#pragma ident "%Z%%M% %I% %E% SMI"
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <stdio.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <stdlib.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <string.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <unistd.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <libdlpi.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <sys/ethernet.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <netinet/in.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include "wpa_impl.h"
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include "eloop.h"
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include "l2_packet.h"
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int
a399b7655a1d835aa8606c2b29e4e777baac8635zflink_init(struct l2_packet_data *l2)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf int retval;
a399b7655a1d835aa8606c2b29e4e777baac8635zf uint8_t paddr[DLPI_PHYSADDR_MAX];
a399b7655a1d835aa8606c2b29e4e777baac8635zf size_t paddrlen = sizeof (paddr);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf retval = dlpi_bind(l2->dh, DLPI_ANY_SAP, NULL);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (retval != DLPI_SUCCESS) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf wpa_printf(MSG_ERROR, "cannot bind on %s: %s",
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2->ifname, dlpi_strerror(retval));
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (-1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf retval = dlpi_promiscon(l2->dh, DL_PROMISC_SAP);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (retval != DLPI_SUCCESS) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf wpa_printf(MSG_ERROR, "cannot enable promiscous"
a399b7655a1d835aa8606c2b29e4e777baac8635zf " mode (SAP) on %s: %s",
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2->ifname, dlpi_strerror(retval));
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (-1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf retval = dlpi_get_physaddr(l2->dh, DL_CURR_PHYS_ADDR, paddr, &paddrlen);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (retval != DLPI_SUCCESS) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf wpa_printf(MSG_ERROR, "cannot get physical address for %s: %s",
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2->ifname, dlpi_strerror(retval));
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (-1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (paddrlen != sizeof (l2->own_addr)) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf wpa_printf(MSG_ERROR, "physical address for %s is not %d bytes",
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2->ifname, sizeof (l2->own_addr));
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (-1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf (void) memcpy(l2->own_addr, paddr, sizeof (l2->own_addr));
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (0);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * layer2 packet handling.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zfint
a399b7655a1d835aa8606c2b29e4e777baac8635zfl2_packet_get_own_addr(struct l2_packet_data *l2, uint8_t *addr)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf (void) memcpy(addr, l2->own_addr, sizeof (l2->own_addr));
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (0);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfint
a399b7655a1d835aa8606c2b29e4e777baac8635zfl2_packet_send(struct l2_packet_data *l2, uint8_t *buf, size_t buflen)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf int retval;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf retval = dlpi_send(l2->dh, NULL, 0, buf, buflen, NULL);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (retval != DLPI_SUCCESS) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf wpa_printf(MSG_ERROR, "l2_packet_send: cannot send "
a399b7655a1d835aa8606c2b29e4e777baac8635zf "message on %s: %s", l2->ifname, dlpi_strerror(retval));
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (-1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (0);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/* ARGSUSED */
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic void
a399b7655a1d835aa8606c2b29e4e777baac8635zfl2_packet_receive(int fd, void *eloop_ctx, void *sock_ctx)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf struct l2_packet_data *l2 = eloop_ctx;
a399b7655a1d835aa8606c2b29e4e777baac8635zf uint64_t buf[IEEE80211_MTU_MAX / sizeof (uint64_t)];
a399b7655a1d835aa8606c2b29e4e777baac8635zf size_t buflen = sizeof (buf);
a399b7655a1d835aa8606c2b29e4e777baac8635zf struct l2_ethhdr *ethhdr;
a399b7655a1d835aa8606c2b29e4e777baac8635zf int retval;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf retval = dlpi_recv(l2->dh, NULL, NULL, buf, &buflen, 0, NULL);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (retval != DLPI_SUCCESS) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf wpa_printf(MSG_ERROR, "l2_packet_receive: cannot receive "
a399b7655a1d835aa8606c2b29e4e777baac8635zf "message on %s: %s", l2->ifname, dlpi_strerror(retval));
a399b7655a1d835aa8606c2b29e4e777baac8635zf return;
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf ethhdr = (struct l2_ethhdr *)buf;
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (buflen < sizeof (*ethhdr) ||
a399b7655a1d835aa8606c2b29e4e777baac8635zf (ntohs(ethhdr->h_proto) != ETHERTYPE_EAPOL &&
a399b7655a1d835aa8606c2b29e4e777baac8635zf ntohs(ethhdr->h_proto) != ETHERTYPE_RSN_PREAUTH))
a399b7655a1d835aa8606c2b29e4e777baac8635zf return;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source,
a399b7655a1d835aa8606c2b29e4e777baac8635zf (unsigned char *)(ethhdr + 1), buflen - sizeof (*ethhdr));
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/* ARGSUSED */
a399b7655a1d835aa8606c2b29e4e777baac8635zfstruct l2_packet_data *
a399b7655a1d835aa8606c2b29e4e777baac8635zfl2_packet_init(const char *ifname, unsigned short protocol,
a399b7655a1d835aa8606c2b29e4e777baac8635zf void (*rx_callback)(void *, unsigned char *, unsigned char *, size_t),
a399b7655a1d835aa8606c2b29e4e777baac8635zf void *rx_callback_ctx)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf int retval;
a399b7655a1d835aa8606c2b29e4e777baac8635zf struct l2_packet_data *l2;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2 = calloc(1, sizeof (struct l2_packet_data));
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (l2 == NULL)
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (NULL);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf (void) strlcpy(l2->ifname, ifname, sizeof (l2->ifname));
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2->rx_callback = rx_callback;
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2->rx_callback_ctx = rx_callback_ctx;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf retval = dlpi_open(l2->ifname, &l2->dh, DLPI_RAW);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (retval != DLPI_SUCCESS) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf wpa_printf(MSG_ERROR, "unable to open DLPI link %s: %s",
a399b7655a1d835aa8606c2b29e4e777baac8635zf l2->ifname, dlpi_strerror(retval));
a399b7655a1d835aa8606c2b29e4e777baac8635zf free(l2);
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (NULL);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf /* NOTE: link_init() sets l2->own_addr */
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (link_init(l2) < 0) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf dlpi_close(l2->dh);
a399b7655a1d835aa8606c2b29e4e777baac8635zf free(l2);
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (NULL);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf (void) eloop_register_read_sock(dlpi_fd(l2->dh), l2_packet_receive, l2,
a399b7655a1d835aa8606c2b29e4e777baac8635zf NULL);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (l2);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfvoid
a399b7655a1d835aa8606c2b29e4e777baac8635zfl2_packet_deinit(struct l2_packet_data *l2)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (l2 == NULL)
a399b7655a1d835aa8606c2b29e4e777baac8635zf return;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf eloop_unregister_read_sock(dlpi_fd(l2->dh));
a399b7655a1d835aa8606c2b29e4e777baac8635zf dlpi_close(l2->dh);
a399b7655a1d835aa8606c2b29e4e777baac8635zf free(l2);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}