bare-socket.c 1.79 KB
Newer Older
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
/*
 * Alessandro Rubini for CERN, 2011 -- public domain
 */

/* Socket interface for bare Linux */
#include <pproto/pproto.h>
#include "bare-linux.h"

/* Receive and send is trivial */
int bare_recv_packet(struct pp_instance *ppi, void *pkt, int len)
{
	return sys_recv(ppi->ch.fd, pkt, len, 0);
}

int bare_send_packet(struct pp_instance *ppi, void *pkt, int len)
{
	return sys_send(ppi->ch.fd, pkt, len, 0);
}

int pp_recv_packet(struct pp_instance *ppi, void *pkt, int len)
	__attribute__((alias("bare_recv_packet")));
int pp_send_packet(struct pp_instance *ppi, void *pkt, int len)
	__attribute__((alias("bare_send_packet")));

#define PF_PACKET 17
#define SOCK_RAW 3

/* To open a channel we must bind to an interface and so on */
int bare_open_ch(struct pp_instance *ppi, char *ifname)
{
	int sock, iindex;
	struct bare_ifreq ifr;
	struct bare_sockaddr_ll addr;

	/* open socket */
	sock = sys_socket(PF_PACKET, SOCK_RAW, PP_PROTO_NR);
	if (sock < 0) {
		pp_diag_error(ppi, bare_errno);
		pp_diag_fatal(ppi, "socket()", "");
	}

	/* hw interface information */
	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_ifrn.ifrn_name, ifname);
	if (sys_ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
		pp_diag_error(ppi, bare_errno);
		pp_diag_fatal(ppi, "ioctl(GIFINDEX)", "");
	}

	iindex = ifr.ifr_ifru.index;
	if (sys_ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
		pp_diag_error(ppi, bare_errno);
		pp_diag_fatal(ppi, "ioctl(GIFHWADDR)", "");
	}
	memcpy(ppi->ch.addr, ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);

	/* bind and setsockopt */
	memset(&addr, 0, sizeof(addr));
	addr.sll_family = PF_PACKET;
	addr.sll_protocol = htons(PP_PROTO_NR);
	addr.sll_ifindex = iindex;
	if (sys_bind(sock, (struct bare_sockaddr *)&addr, sizeof(addr)) < 0) {
		pp_diag_error(ppi, bare_errno);
		pp_diag_fatal(ppi, "bind", "");
	}

	ppi->ch.fd = sock;
	return 0;
}