plc(Power Line Communication)通信测试程序
plconfig.c
/*
plconfig.c version 0.2
Source code for Intellon-based Powerline bridge configuration tool
Copyright (C) 2002-2003 Manuel Kasper <mk@neon1.net>.
All rights reserved.
*/
/*
* Linux specific code by Enrik Berkhan <enrik.berkhan@inka.de>
* Copyright (C) 2004 Manuel Kasper <mk@neon1.net>.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#ifdef LINUX
#include <linux/types.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <string.h>
#include <signal.h>
#else
#include <net/bpf.h>
#endif
#include <sys/socket.h>
#include <net/if.h>
#include <stdio.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include "global.h"
#include "md5.h"
#define PLCONFIG_VERSION "0.2"
#define ETHERTYPE_INTELLON 0x88E1
#define logictostr(x) (x) ? "yes" : "no"
#ifndef LINUX
/* bpf instructions to filter for Intellon ethertype packets */
struct bpf_insn insns[] = {
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_INTELLON, 0, 1),
BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
BPF_STMT(BPF_RET+BPF_K, 0)
};
#endif
u_short ex_word(u_char *ptr) {
return ntohs(*((u_short*)ptr));
}
u_long ex_long(u_char *ptr) {
return ntohl(*((u_long*)ptr));
}
char *format_mac_addr(u_char *addr, char *macbuf) {
sprintf(macbuf, "%02x:%02x:%02x:%02x:%02x:%02x",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
return macbuf;
}
void dump_params_and_stats(u_char *macmgmt) {
printf(" Tx ACK Counter: %u\n"
" Tx NACK Counter: %u\n"
" Tx FAIL Counter: %u\n"
" Tx Contention Loss Counter: %u\n"
" Tx Collision Counter: %u\n"
" Tx CA3 Latency Counter: %u\n"
" Tx CA2 Latency Counter: %u\n"
" Tx CA1 Latency Counter: %u\n"
" Tx CA0 Latency Counter: %u\n"
" Rx Cumul. Bytes per 40-symbol Packet Counter: %lu\n",
ex_word(&macmgmt[2]), ex_word(&macmgmt[4]), ex_word(&macmgmt[6]),
ex_word(&macmgmt[8]), ex_word(&macmgmt[10]), ex_word(&macmgmt[12]),
ex_word(&macmgmt[14]), ex_word(&macmgmt[16]), ex_word(&macmgmt[18]),
ex_long(&macmgmt[20]));
}
void dump_network_statistics(u_char *macmgmt) {
int da;
u_char *stat;
char macbuf[20];
for (da = 0; da < 15; da++) {
stat = (macmgmt+9+da*12);
/* Check to see if that node entry is valid -
stupid Intellon chip is supposed to return 00:00:00:00:00:00 for
nonexistant nodes (as per the specs), but instead it returns
01:00:00:00:00:00 so we just skip checking the first byte,
since heaven knows what else it may return instead of 01 in
other places/revisions.
*/
if (!((stat[1] == 0) && (stat[2] == 0) &&
(stat[3] == 0) && (stat[4] == 0) && (stat[5] == 0))) {
printf("\n Statistics for Network DA #%d:\n"
" MAC address: %s\n"
" Bytes in 40 symbols: %u\n"
" FAILS received: %u\n"
" Frame Drops: %u\n",
da+1, format_mac_addr(stat, macbuf), ex_word(&stat[6]),
ex_word(&stat[8]), ex_word(&stat[10]));
}
}
}
void dump_tx_characteristics(u_char *macmgmt) {
char *retrtab[] = {
"Transmit without retries",
"Transmit with one retry only",
"Transmit with normal retries (HomePlug)", "Reserved"};
printf(" Local consumption only: %s\n"
" Encryption flag: %s\n"
" Transmit priority: %u\n"
" Response expected: %s\n"
" Transmit contention free: %s\n"
" Retry control: %s\n"
" No default encryption receive: %s\n"
" No unencrypted receive: %s\n"
" Transmit EKS: %u\n",
logictostr(macmgmt[2] & 0x80), logictostr(macmgmt[2] & 0x40),
(macmgmt[2] >> 4) & 0x03, logictostr(macmgmt[2] & 0x08),
logictostr(macmgmt[2] & 0x04), retrtab[(macmgmt[3] >> 6) & 0x03],
logictostr(macmgmt[3] & 0x08), logictostr(macmgmt[3] & 0x04),
macmgmt[4]);
}
void dump_set_key(u_char *macmgmt) {
char asckey[17];
char *hextab = "0123456789abcdef";
int i;
/* Convert the key to ASCII hex */
for (i = 0; i < 8; i++) {
asckey[i<<1] = hextab[(macmgmt[i+3] >> 4) & 0x0F];
asckey[(i<<1)+1] = hextab[macmgmt[i+3] & 0x0F];
}
asckey[16] = 0;
printf(" Encryption key select: 0x%02x\n"
" Network encryption key: %s\n",
macmgmt[2], asckey);
}
void read_display_responses(int netfd, u_char *framebuf, u_int buflen) {
u_char *frameptr;
ssize_t rdlen;
u_int i, j;
#ifdef LINUX
struct sockaddr_ll addr;
socklen_t addrlen = sizeof(addr);
#else
struct bpf_hdr *header;
#endif
char macbuf[20];
/* read responses */
while (1) {
#ifdef LINUX
rdlen = recvfrom(netfd, framebuf+ETHER_HDR_LEN, buflen-ETHER_HDR_LEN, MSG_TRUNC, (struct sockaddr *)&addr, &addrlen);
#else
rdlen = read(netfd, framebuf, buflen);
#endif
if (rdlen != -1) {
#ifdef LINUX
if (rdlen > buflen-ETHER_HDR_LEN) {
fprintf(stderr, "received jumbo frame of %d bytes len, truncated\n", rdlen);
}
frameptr = framebuf;
memcpy(framebuf+6, &addr.sll_addr, 6);
if (addr.sll_pkttype != PACKET_OUTGOING &&
addr.sll_protocol == htons(ETHERTYPE_INTELLON)) {
#else
header = (struct bpf_hdr*)framebuf;
frameptr = framebuf + header->bh_hdrlen;
if ((frameptr[12] == 0x88) && (frameptr[13] == 0x7B)) {
#endif
/* It's an intellon packet - read MAC management entries */
j = 15;
for (i = 0; i < (frameptr[14] & (u_int)0x7F); i++) {
switch (frameptr[j]) {
case 0x04: /* Set Network Encryption Key */
printf("\n- Set Network Encryption Key from %s\n",
format_mac_addr(&frameptr[6], macbuf));
dump_set_key(&frameptr[j]);
break;
case 0x07: /* Request Parameters and Statistics */
printf("\n- Parameters and Statistics request from %s\n",
format_mac_addr(&frameptr[6], macbuf));
break;
case 0x08: /* Parameters and Statistics Respo