121 lines
4.3 KiB
Racket
121 lines
4.3 KiB
Racket
#lang imperative-syndicate
|
|
;; Ethernet driver
|
|
|
|
(provide (struct-out available-ethernet-interface)
|
|
(struct-out ethernet-interface)
|
|
(struct-out ethernet-packet)
|
|
zero-ethernet-address
|
|
broadcast-ethernet-address
|
|
ethernet-packet-pattern)
|
|
|
|
(require/activate imperative-syndicate/drivers/timer)
|
|
(require racket/set)
|
|
(require racket/match)
|
|
(require racket/async-channel)
|
|
|
|
(require packet-socket)
|
|
(require bitsyntax)
|
|
|
|
(require "configuration.rkt")
|
|
(require "dump-bytes.rkt")
|
|
(require imperative-syndicate/pattern-expander)
|
|
|
|
(assertion-struct available-ethernet-interface (name))
|
|
(assertion-struct ethernet-interface (name hwaddr))
|
|
(message-struct ethernet-packet (interface-name from-wire? source destination ethertype body))
|
|
|
|
(define zero-ethernet-address (bytes 0 0 0 0 0 0))
|
|
(define broadcast-ethernet-address (bytes 255 255 255 255 255 255))
|
|
|
|
(define interface-names (raw-interface-names))
|
|
(log-info "Device names: ~a" interface-names)
|
|
|
|
(define (spawn-ethernet-driver)
|
|
(spawn #:name 'ethernet-driver
|
|
|
|
(for [(n interface-names)]
|
|
(assert (available-ethernet-interface n)))
|
|
|
|
(during/spawn
|
|
(observe (ethernet-packet $interface-name #t _ _ _ _))
|
|
#:name (list 'ethernet-interface interface-name)
|
|
|
|
(define h (raw-interface-open interface-name))
|
|
(when (not h) (error 'ethernet "Couldn't open interface ~v" interface-name))
|
|
(log-info "Opened interface ~a, yielding handle ~v" interface-name h)
|
|
|
|
(assert (ethernet-interface interface-name (raw-interface-hwaddr h)))
|
|
|
|
(define control-ch (make-async-channel))
|
|
(thread (lambda () (interface-packet-read-loop interface-name h control-ch)))
|
|
(signal-background-activity! +1)
|
|
(on-start (async-channel-put control-ch 'unblock))
|
|
(on-stop (async-channel-put control-ch 'quit))
|
|
|
|
;; (on (message ($ p (ethernet-packet interface #t _ _ _ _)))
|
|
;; (log-info "Interface ~a inbound packet ~a -> ~a (type 0x~a)"
|
|
;; (ethernet-interface-name (ethernet-packet-interface p))
|
|
;; (pretty-bytes (ethernet-packet-source p))
|
|
;; (pretty-bytes (ethernet-packet-destination p))
|
|
;; (number->string (ethernet-packet-ethertype p) 16))
|
|
;; (log-info "~a" (dump-bytes->string (ethernet-packet-body p))))
|
|
|
|
(on (message ($ p (ethernet-packet interface-name #f _ _ _ _)))
|
|
;; (log-info "Interface ~a OUTBOUND packet ~a -> ~a (type 0x~a)"
|
|
;; (ethernet-interface-name (ethernet-packet-interface p))
|
|
;; (pretty-bytes (ethernet-packet-source p))
|
|
;; (pretty-bytes (ethernet-packet-destination p))
|
|
;; (number->string (ethernet-packet-ethertype p) 16))
|
|
;; (log-info "~a" (dump-bytes->string (ethernet-packet-body p)))
|
|
(raw-interface-write h (encode-ethernet-packet p))))))
|
|
|
|
(define (interface-packet-read-loop interface-name h control-ch)
|
|
(define (blocked)
|
|
(match (async-channel-get control-ch)
|
|
['unblock (unblocked)]
|
|
['quit (void)]))
|
|
(define (unblocked)
|
|
(match (async-channel-try-get control-ch)
|
|
['unblock (unblocked)]
|
|
['quit (void)]
|
|
[#f
|
|
(define p (raw-interface-read h))
|
|
(define decoded (decode-ethernet-packet interface-name p))
|
|
(when decoded (ground-send! decoded))
|
|
(unblocked)]))
|
|
(blocked)
|
|
(raw-interface-close h)
|
|
(signal-background-activity! -1))
|
|
|
|
(define (decode-ethernet-packet interface-name p)
|
|
(bit-string-case p
|
|
([ (destination :: binary bytes 6)
|
|
(source :: binary bytes 6)
|
|
(ethertype :: integer bytes 2)
|
|
(body :: binary) ]
|
|
(ethernet-packet interface-name
|
|
#t
|
|
(bit-string->bytes source)
|
|
(bit-string->bytes destination)
|
|
ethertype
|
|
(bit-string->bytes body)))
|
|
(else #f)))
|
|
|
|
(define (encode-ethernet-packet p)
|
|
(match-define (ethernet-packet _ _ source destination ethertype body) p)
|
|
(bit-string->bytes
|
|
(bit-string (destination :: binary bytes 6)
|
|
(source :: binary bytes 6)
|
|
(ethertype :: integer bytes 2)
|
|
(body :: binary))))
|
|
|
|
(begin-for-declarations
|
|
(define-pattern-expander ethernet-packet-pattern
|
|
(syntax-rules ()
|
|
[(_ interface-name from-wire? ethertype)
|
|
(ethernet-packet interface-name from-wire? _ _ ethertype _)])))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(spawn-ethernet-driver)
|