+++ http://developerweb.net/viewtopic.php?id=3704
this is the structure defining the protocol:
struct arphdr_t
{
	unsigned short	ar_hrd;    // 2
	unsigned short	ar_pro;    // 2
	unsigned char   ar_hln;    // 1
	unsigned char   ar_pln;    // 1
	unsigned short	ar_op;     // 2
	unsigned char   ar_sha[6]; // 6
	unsigned char   ar_sip[4]; // 4
	unsigned char   ar_tha[6]; // 6
	unsigned char   ar_tip[4]; // 4
};

2 functions I use to send & recv messages over UDP :

int 
common_send_message(int sd, unsigned char* msg, int msg_len, unsigned char mac[], int interface, int pkttype)
{
	fd_set			writefs;
	struct timeval		tv;
	struct msghdr		msgs;
	struct iovec		iov;
	struct sockaddr_ll	socknfo;
	int			len, fdv;
	
	memset(&msgs, '\0', sizeof(struct msghdr));
	msgs.msg_name = &socknfo;
	msgs.msg_namelen = sizeof(struct sockaddr_ll);
	
	msgs.msg_iovlen = 1;
	msgs.msg_iov = &iov;
	
	iov.iov_len = msg_len;
	iov.iov_base = msg;
	
	socknfo.sll_family	= AF_PACKET;
	socknfo.sll_protocol	= htons(ETH_P_RARP);
	socknfo.sll_ifindex	= interface;
	socknfo.sll_hatype	= 0;
	socknfo.sll_pkttype	= pkttype;
	socknfo.sll_halen	= 6;
	
	socknfo.sll_addr[0] = mac[0] ;
	socknfo.sll_addr[1] = mac[1] ;
	socknfo.sll_addr[2] = mac[2] ;
	socknfo.sll_addr[3] = mac[3] ;
	socknfo.sll_addr[4] = mac[4] ;
	socknfo.sll_addr[5] = mac[5] ;
	
	FD_ZERO( &writefs ) ;
	FD_SET( sd, &writefs ) ;
	tv.tv_sec = 30 ; // 30 seconds
	tv.tv_usec = 0 ;
	fdv = select( sd+1, NULL, &writefs, NULL, &tv ) ;
	if ( fdv == 0 || !FD_ISSET( sd, &writefs ) )
	{
		printf( "Send timed out [30 seconds]\n" ) ;
		return -1;
	}
	return (int)sendmsg(sd, &msgs, 0);

}

int 
common_recv_message(int sd, unsigned char* data, int maxlen, unsigned char mac[])
{
	fd_set			readfs;
	struct timeval		tv;
	struct msghdr		msgs;
	struct iovec		iov;
	struct sockaddr_ll	socknfo;
	int			len, fdv;
	
	memset(&msgs, '\0', sizeof(struct msghdr));
	msgs.msg_name		  = &socknfo;
	msgs.msg_namelen	= sizeof(struct sockaddr_ll);
	msgs.msg_iovlen		= 1;
	msgs.msg_iov		  = &iov;
	
	iov.iov_len		  = maxlen;
	iov.iov_base		= data;
	
	tv.tv_sec 		= 30; // 30 seconds
	tv.tv_usec		= 0;
	FD_ZERO(&readfs);
	FD_SET(sd, &readfs);
	fdv = select(sd+1, &readfs, NULL, NULL, &tv);
	if(fdv == 0 || !FD_ISSET(sd, &readfs))
	{
		printf("Read timed out [30 seconds]\n");
		return -1;
	}
	len = recvmsg(sd, &msgs, 0);
	memcpy(mac, socknfo.sll_addr, 6);
	
	return len;

}

to find out the interface index you must use :

int common_find_interface(const char* name)
{
	struct ifreq	ifr;
	int		iindex = 1;
	int		sock = socket(PF_PACKET, SOCK_RAW, 0);
	
	ifr.ifr_ifindex	= iindex;
	while(ioctl(sock, SIOCGIFNAME, &ifr) == 0)
	{
		if(strcmp(ifr.ifr_name, name) == 0)
		{
			close(sock);
			return iindex;
		}
		ifr.ifr_ifindex = ++iindex;
	}
	
	close(sock);
	return -1;
}

You don't need to use raw sockets. It is easier to use SOCK_DGRAM because you must not implement ethernet protocol