Communicating with HomePlugAV Devices using Python

I've got a couple of pairs of ON Networks' PL 500 HomePlugAV Powerline Adapters and have been playing around with them to see how they compare to the Computrend 902 devices I played around with 5 years ago.

I'm still playing around with the kit, but thought I'd document a very basic example of how to send commands to the devices using Python - the instructions should work for any kit based on Qualcomm's INT6x00 and AR7x00 chipsets (mine use the AR7420/QCA7420) - we'll be changing one of the encryption keys (the NMK) that the devices use



As all management communication is via ethernet frames, we'll need to craft packets using a raw socket. The easiest way to do this is to use scapy.

As we're opening a raw socket, you'll need to run the script as root.


Setting the Encryption Key

As a simple example, we're going to set the Network Management Key (NMK). It forms a good example as we're not expecting a response so can focus on building the request rather than also having to listen for the response.

#!/usr/bin/env python
# Copyright (C) 2014 B Tasker

import sys
# sys.path.append('Scapy') # Uncomment this if you've got Scapy in a subdirectory rather than installed system wide

from scapy.all import *
from scapy.utils import rdpcap
import fcntl, socket, struct

iface='eth0' # Which interface should we use

# Function from
def getHwAddr(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', ifname[:15]))
    return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]

# We'll set the encryption key (NMK) to 'HomePlugAV' - 50D3E4933F855B7040784DF815AA8DB7
# To generate a NMK, use hpavkey from open-plc-utils (
# hpavkey -M HomePlugAV
# 50D3E4933F855B7040784DF815AA8DB7
# hpavkey -M StrongPassword
# 5A11F2E2B1FDA8ABFADA70B4B1B8C674

data_list = payload.split(":")

# Break down of payload used above
# '00' - MAC Management header (Version: 1) - they're zero indexed
# '50:a0' - Request is AxA050 (Encryption key set request)
# 'b0:52' - OUI
# '01' - EKS (in this case - Unknown 0x01)
# '50:d3:e4:93:3f:85:5b:70:40:78:4d:f8:15:aa:8d:b7' - Desired Crypto key (the NMK)
# '0f' - Payload encryption key select (0x0f)
# '00:00:00:00:00:00' - Destination Address
# '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00' - DAK (empty in this case)

# Build and send the packet
p = Ether()
p.dst='00:B0:52:00:00:01'; # Only the nearest HomeplugAV device will respond
p.type=0x88e1; # HomeplugAV management frame
b = p/data

If you run the script, the key on your local powerline device should be set to 'HomePlugAV'. Only the local device will have changed as we've used the MAC 00:B0:52:00:00:01. The reason we've done this is that it's far more complicated to change the NMK on a remote powerline device (so the example script would have been much, much longer).

If you watch with tcpdump, you should see something similar to the following

tcpdump -i eth0 ether dst host '00:B0:52:00:00:01'

17:37:46.776878 00:1e:a0:cf:87:18 (oui Unknown) > 00:b0:52:00:00:01 (oui Unknown), ethertype Unknown (0x88e1), length 60: 
	0x0000:  0050 a000 b052 0150 d3e4 933f 855b 7040  .P...R.P...?.[p@
	0x0010:  784d f815 aa8d b70f 0000 0000 0000 0000  xM..............
	0x0020:  0000 0000 0000 0000 0000 0000 0000       ..............

The key should also have changed on the local powerline device.