Icnluded USB host connect/disconnect trigger based on modded dwc2 kernel module

This commit is contained in:
MaMe82 2018-09-28 01:36:57 +02:00
parent 073e96de12
commit eeb127c290
4 changed files with 302 additions and 18 deletions

View File

@ -3,12 +3,9 @@
package main
import (
"log"
"strconv"
"time"
"fmt"
"github.com/mame82/P4wnP1_go/service"
"log"
"os"
"os/signal"
"syscall"
@ -37,7 +34,7 @@ func main() {
}
svc.Start()
/*
// ToDo: Remove this (testing only)
//Send some log messages for testing
textfill := "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea"
@ -50,7 +47,7 @@ func main() {
i++
}
}()
*/
//use a channel to wait for SIGTERM or SIGINT
fmt.Println("P4wnP1 service initialized, stop with SIGTERM or SIGINT")

109
service/connect_watcher.go Normal file
View File

@ -0,0 +1,109 @@
package service
import (
"fmt"
"github.com/mame82/P4wnP1_go/common_web"
"github.com/mame82/P4wnP1_go/service/dwc2"
)
/*
Needs modified dwc2 kernel module, sending multicast netlink messages to group 24
The initial connection state is undefined, the event is fired based on an IRQ of the gadget core (not in host mode)
which has the USBRST flag set if a host connection occurs or unset if a disconnection occurs.
As these IRQs are triggered, as soon as a new gadget is deployed, the state wouldn't stay undefined, once the USB
stack has initialized the gadget settings.
The mentioned IRQ fires multiple times:
On disconnect: two times 0x00000000
On connect: 0x00000000 followed by two times 0x00001000
To cope with that behavior, we only fire an event if the new state differs from the last one
*/
const (
mcast_group = 24
host_connected = uint32(0x00001000)
host_disconnected = uint32(0x00000000)
)
type Dwc2ConnectWatcher struct {
rootSvc *Service
isRunning bool
connected bool
nl *dwc2.Dwc2Netlink
firstUpdateDone bool
}
func (d * Dwc2ConnectWatcher) udateNeeded(newStateConnected bool) (needed bool) {
if !d.firstUpdateDone {
d.firstUpdateDone = true
return true
}
return newStateConnected != d.connected
}
func (d * Dwc2ConnectWatcher) update(newStateConnected bool) {
d.connected = newStateConnected
// --> here a event could be triggered (in case the event manager is registered)
if d.connected {
fmt.Println("Connected to USB host")
d.rootSvc.SubSysEvent.Emit(ConstructEventTrigger(common_web.EVT_TRIGGER_TYPE_USB_GADGET_CONNECTED))
d.rootSvc.SubSysEvent.Emit(ConstructEventLog("USB watcher", 1, "Connected to USB host"))
} else {
fmt.Println("Disconnected from USB host")
d.rootSvc.SubSysEvent.Emit(ConstructEventTrigger(common_web.EVT_TRIGGER_TYPE_USB_GADGET_DISCONNECTED))
d.rootSvc.SubSysEvent.Emit(ConstructEventLog("USB watcher", 1, "Disconnected from USB host"))
}
}
func (d * Dwc2ConnectWatcher) evt_loop() {
for d.isRunning {
indata := d.nl.Read()
if len(indata) != 4 {
continue // ignore, we want tor receive an uint32
}
val := dwc2.Hbo().Uint32(indata)
switch val {
case host_connected:
if d.udateNeeded(true) {
d.update(true)
}
case host_disconnected:
if d.udateNeeded(false) {
d.update(false)
}
default:
fmt.Println("Unknown value from DWC2: ", val)
}
}
}
func (d * Dwc2ConnectWatcher) IsConnected() bool {
return d.connected
}
func (d * Dwc2ConnectWatcher) Start() {
d.nl.OpenNlKernelSock()
d.isRunning = true
go d.evt_loop()
}
func (d * Dwc2ConnectWatcher) Stop() {
d.isRunning = false
d.nl.Close()
}
func NewDwc2ConnectWatcher(rootSvc *Service) (d *Dwc2ConnectWatcher) {
d = &Dwc2ConnectWatcher{
nl: dwc2.NewDwc2Nl(24),
rootSvc: rootSvc,
}
return d
}

View File

@ -0,0 +1,168 @@
package dwc2
import (
"encoding/binary"
"fmt"
"golang.org/x/sys/unix"
"os"
"syscall"
"unsafe"
)
var hbo = HostByteOrder()
func Hbo() binary.ByteOrder {
return hbo
}
type Dwc2Netlink struct {
sock_fd int
nl_group int
}
func NewDwc2Nl(mcast_group int) (d* Dwc2Netlink) {
return &Dwc2Netlink{
nl_group: mcast_group,
}
}
func (d *Dwc2Netlink) OpenNlKernelSock() (err error) {
d.sock_fd,err = unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, unix.NETLINK_USERSOCK)
if err != nil { return }
err = unix.Bind(d.sock_fd, &unix.SockaddrNetlink{
Family: unix.AF_NETLINK,
Groups: 0,
Pid: uint32(os.Getpid()),
})
if err != nil { return }
err = syscall.SetsockoptInt(d.sock_fd, unix.SOL_NETLINK, unix.NETLINK_ADD_MEMBERSHIP, d.nl_group)
return
}
func (d *Dwc2Netlink) Close() (err error) {
return unix.Close(d.sock_fd)
}
func (d *Dwc2Netlink) socketReaderLoop() {
fmt.Println("Readloop started")
rcvBuf := make([]byte, 1024)
for {
fmt.Println("READER LOOP")
n, err := syscall.Read(d.sock_fd, rcvBuf)
if err != nil || n == 0 {
d.Close()
fmt.Println("Error reading from socket")
break
}
nlMsg := make([]byte, n)
copy(nlMsg, rcvBuf) // Copy over as many bytes as readen
fmt.Printf("Received packet %+v\n", nlMsg)
/*
//fmt.Printf("Sending raw event packet to handler loop: %+v\n", nlMsg)
select {
case m.newRawPacket <- nlMsg:
// do nothing
case <-m.disposeMgmtConnection:
// unblock and exit the loop if eventHandler is closed
close(m.newRawPacket)
break
}
*/
}
fmt.Println("Socket read loop exited")
}
func (d *Dwc2Netlink) SocketReaderLoop2() {
fmt.Println("Readloop started")
rcvBuf := make([]byte, os.Getpagesize())
for {
//fmt.Println("calling receive")
// peek into rcv to fetch bytes available
n,_,_ := unix.Recvfrom(d.sock_fd, rcvBuf, unix.MSG_PEEK)
//fmt.Println("Bytes received: ", n)
if len(rcvBuf) < n {
fmt.Println("Receive buffer too small, increasing...")
rcvBuf = make([]byte, len(rcvBuf)*2)
} else {
n,_,_ = unix.Recvfrom(d.sock_fd, rcvBuf, 0)
nlMsgRaw := make([]byte, n)
copy(nlMsgRaw, rcvBuf) // Copy over as many bytes as readen
fmt.Printf("Received packet %+v\n", nlMsgRaw)
msg := NlMsg{}
msg.fromWire(nlMsgRaw)
fmt.Printf("Received message %+v\n", msg)
}
}
fmt.Println("Socket read loop exited")
}
func (d *Dwc2Netlink) Read() (res []byte) {
rcvBuf := make([]byte, os.Getpagesize())
for {
//fmt.Println("calling receive")
// peek into rcv to fetch bytes available
n,_,_ := unix.Recvfrom(d.sock_fd, rcvBuf, unix.MSG_PEEK)
//fmt.Println("Bytes received: ", n)
if len(rcvBuf) < n {
fmt.Println("Receive buffer too small, increasing...")
rcvBuf = make([]byte, len(rcvBuf)*2)
} else {
break
}
}
n,_,_ := unix.Recvfrom(d.sock_fd, rcvBuf, 0)
nlMsgRaw := make([]byte, n)
copy(nlMsgRaw, rcvBuf) // Copy over as many bytes as readen
msg := NlMsg{}
msg.fromWire(nlMsgRaw)
return msg.Payload
}
type NlMsg struct {
Length uint32
Type uint16
Flags uint16
SeqNum uint32
PortID uint32 // == Process ID for first socket of Proc. If the message comes from kernel (like here) PortID is 0
Payload []byte
}
// Note: data is formated in host byte order, unless the attribute NLA_F_NET_BYTEORDER is specified
func (m *NlMsg) fromWire(src []byte) {
m.Length = hbo.Uint32(src[0:4])
// truncate message to length
src = src[:m.Length]
m.Type = hbo.Uint16(src[4:6])
m.Flags = hbo.Uint16(src[6:8])
m.SeqNum = hbo.Uint32(src[8:12])
m.PortID = hbo.Uint32(src[12:16])
m.Payload = src[16:]
}
func HostByteOrder() (res binary.ByteOrder) {
i := int(0x0100)
ptr := unsafe.Pointer(&i)
if 0x01 == *(*byte)(ptr) {
return binary.BigEndian
}
return binary.LittleEndian
}

View File

@ -98,11 +98,10 @@ func RegisterDefaultTriggerActions(tam *TriggerActionManager) {
tam.AddTriggerAction(logSSHLogin)
}
type Service struct {
SubSysDataStore *datastore.Store // very first service
// SubSysState interface{}
// SubSysLogging interface{}
SubSysDataStore *datastore.Store // very first service
// SubSysState interface{}
// SubSysLogging interface{}
SubSysNetwork *NetworkManager
SubSysEvent *EventManager
@ -112,35 +111,46 @@ type Service struct {
SubSysBluetooth *BtService
SubSysRPC *server
SubSysTriggerActions *TriggerActionManager
SubSysDwc2ConnectWatcher *Dwc2ConnectWatcher
}
func NewService() (svc *Service, err error) {
svc = &Service{}
svc.SubSysDataStore,err = datastore.Open(pPATH_DATA_STORE)
if err != nil { return nil,err}
svc.SubSysDataStore, err = datastore.Open(pPATH_DATA_STORE)
if err != nil {
return nil, err
}
svc.SubSysEvent = NewEventManager(20)
svc.SubSysLed = NewLedService()
svc.SubSysNetwork, err = NewNetworkManager()
if err != nil { return nil,err}
svc.SubSysUSB,err = NewUSBGadgetManager(svc) //Depends on NetworkSubSys, EvenSubSys
// if err == ErrUsbNotUsable { err = nil } //ToDo: delete this
if err != nil { return nil,err}
if err != nil {
return nil, err
}
svc.SubSysUSB, err = NewUSBGadgetManager(svc) //Depends on NetworkSubSys, EvenSubSys
// if err == ErrUsbNotUsable { err = nil } //ToDo: delete this
if err != nil {
return nil, err
}
svc.SubSysWifi = NewWifiService(svc) //Depends on NetworkSubSys
svc.SubSysBluetooth = NewBtService(svc) //Depends on NetworkSubSys
svc.SubSysRPC = NewRpcServerService(svc) //Depends on all other
svc.SubSysRPC = NewRpcServerService(svc) //Depends on all other
svc.SubSysTriggerActions = NewTriggerActionManager(svc) //Depends on EventManager, UsbGadgetManager (to trigger HID scripts)
svc.SubSysDwc2ConnectWatcher = NewDwc2ConnectWatcher(svc) // Depends on EventManager, should be started before USB gadget settings are deployed (to avoid missing initial state change)
return
}
func (s *Service) Start() {
s.SubSysEvent.Start()
s.SubSysDwc2ConnectWatcher.Start()
s.SubSysLed.Start()
s.SubSysRPC.StartRpcServerAndWeb("0.0.0.0", "50051", "8000", "/usr/local/P4wnP1/www") //start gRPC service
s.SubSysTriggerActions.Start()
@ -160,6 +170,6 @@ func (s *Service) Stop() {
s.SubSysLed.Stop()
s.SubSysBluetooth.StopNAP()
s.SubSysDwc2ConnectWatcher.Stop()
s.SubSysEvent.Stop()
}