! Ether module for INet process, GDMR, Feb/March 1987. %constinteger char buffer size = 120 %conststring(31) ether device name = "INET__ETHER_DEVICE" %ownstring(15) ether device = "" %ownrecord(ether address fm) our ether address = 0 %ownrecord(ether address fm) ether broadcast = 0 %owninteger ether IP channel = 0 %owninteger ether ARP channel = 0 %constinteger ether IP efn = 32 %constinteger ether ARP efn = 33 %constinteger ether TX efn = 34 %constinteger ARP timer efn = 35 %predicate same ether address(%record(ether address fm)%name a, b) %integer i %for i = 0, 1, 5 %cycle %false %unless a_x(i) = b_x(i) %repeat %true %end ! Ether IP-packet handlers first %routine ether start IP receive %externalintegerspec IP arrived %alias "ETHER__IP_ARRIVED" %externalintegerspec IP params %alias "IP__PARAMS" %externalintegerspec IP params size %alias "IP__PARAMS_SIZE" %record(desc fm) d %record(IOSB fm) IOSB %record(buffer fm)%name buffer %integer status, resetting = 0 !! printstring("Ether start IP receive"); newline buffer == claim buffer reset: status = QIO(ether IP efn, ether IP channel, IO readvblk, buffer_IOSB, addr(IP arrived), addr(buffer), addr(buffer_data(0)), 1500, 0, 0, addr(buffer_ether addrs) , 0) %if status & 1 = 0 %start %signal 15, status %if resetting # 0; ! Failed tell network operator("Attempting to restart IP ether channel...") d_l = IP params size; d_a = addr(IP params) status = QIOW(ether IP efn, ether IP channel, IO setmode ! IOM ctrl ! IOM startup, IOSB, 0, 0, 0, addr(d), 0, 0, 0, 0) %signal 15, status %if status & 1 = 0 %signal 15, IOSB_status %if IOSB_status & 1 = 0 resetting = 1 -> reset %finish %end %externalroutine ether IP arrived %alias "ETHER__IP_ARRIVED" %c (%record(buffer fm)%name ether IP buffer) !! printstring("Ether IP arrived: "); phex(addr(ether IP buffer)); newline enqueue buffer(ether IP buffer, ether inbound queue) wake(0, 0) ether start IP receive %end %routine ether inbound(%record(buffer fm)%name b) !! printstring("Ether inbound: "); write(b_IOSB_length, 0) !! printstring(" from "); print ether address(b_ether addrs_source) !! newline !! dump(b_data(0), b_IOSB_length) %if b_IOSB_status & 1 = 0 %start !! printstring("Ether status "); phex(b_IOSB_status); newline tell network operator("IP ether receive error " . itos(b_IOSB_status, 0)) sp_ether errors in = sp_ether errors in + 1 release buffer(b) %return %finish b_bytes = b_IOSB_length b_IP header == record(addr(b_data(0))) %if b_ether addrs_destination_x(0) & 1 = 0 %start ! Sent directly to us !! printstring("Direct to us"); newline sp_ether packets in = sp_ether packets in + 1 sp_ether bytes in = sp_ether bytes in + b_bytes %else ! Broadcast/multicast !! printstring("Broadcast"); newline sp_ether m packets in = sp_ether m packets in + 1 sp_ether m bytes in = sp_ether m bytes in + b_bytes %finish enqueue buffer(b, IP inbound queue) %end %routinespec start ARP timer %routine ether outbound(%record(buffer fm)%name b) %record(peer info fm)%name target %record(buffer fm)%name x %record(ARP fm) ARP %record(IOSB fm) IOSB %integer status, host, net, class %if b_IP peer = our address %start ! Loopback !! printstring("Loopback "); write(b_bytes, 0); newline !! dump(byteinteger(addr(b_IP header)), b_bytes) x == claim buffer; copy all(b, x) x_ether addrs_source = our ether address x_ether addrs_destination = our ether address x_next queue == nil enqueue buffer(x, IP inbound queue) %if b_next queue == nil %start release buffer(b) %else b_stamp = msecs timestamp %if b_flags & requeue flag # 0 %start requeue buffer(b, b_next queue) %else enqueue buffer(b, b_next queue) %finish %finish %else b_bytes = 46 %if b_bytes < 46 split INet address(b_IP peer, host, net, class) %if net = our network %start target == b_p %else b_p_flags = b_p_flags ! peer gated target == find gateway(net) release buffer(b) %and %return %if target == nil %finish %if target_flags & peer ether address known = 0 %start ! Nothing known about this one yet %if b_ARP lives <= 0 %start ! This one has timed out !! pdate !! printstring("ARP timeout for ") !! print inet address(b_IP peer); newline %if b_protocol = IP TCP protocol %start delete TCB(b_TCB, timeout error); !<<<<<<<<<<<<< %finish b_p_flags = 0; ! Assume now unknown release buffer(b) sp_ARP timeouts = sp_ARP timeouts + 1 %return %finish !! printstring("Sending ARP request for ") !! print inet address(b_IP peer) !! %if target ## b_p %start !! printstring(" gateway "); print INet address(target_address) !! %finish !! newline target_ARP out = target_ARP out + 1 ARP_format = ARP ether protocol ARP_protocol = ARP IP type ARP_hardware length = 6 ARP_protocol length = 4 ARP_op = ARP request code ARP_source hardware = our ether address ARP_source protocol = our address ARP_target hardware = 0 ARP_target protocol = target_address {N} net order short(ARP_format) {N} net order short(ARP_protocol) {N} net order short(ARP_op) {N} net order long(ARP_source protocol) {N} net order long(ARP_target protocol) sp_ARP out = sp_ARP out + 1 status = QIOW(ether TX efn, ether ARP channel, IO writevblk, IOSB, 0, 0, addr(ARP), 46, 0, 0, addr(ether broadcast), 0) %if status & 1 = 0 %or IOSB_status & 1 = 0 %start sp_ARP errors out = sp_ARP errors out + 1 ! ... but queue it anyway... %finish b_ARP lives = b_ARP lives - 1 enqueue buffer(b, ether pending ARP queue) start ARP timer %return %finish !! printstring("Sending "); write(b_bytes, 0) !! printstring(" to "); print ether address(target_ether address) !! newline !! dump(byteinteger(addr(b_IP header)), b_bytes) sp_ether packets out = sp_ether packets out + 1 sp_ether bytes out = sp_ether bytes out + b_bytes status = QIOW(ether TX efn, ether IP channel, IO writevblk, IOSB, 0, 0, addr(b_IP header), b_bytes, 0, 0, addr(target_ether address), 0) %if status & 1 = 0 %or IOSB_status & 1 = 0 %start !! printstring("Ether TX status "); phex(status) !! space; phex(IOSB_status); newline sp_ether errors out = sp_ether errors out + 1 %finish %if b_next queue == nil %start release buffer(b) %else b_stamp = msecs timestamp %if b_flags & requeue flag # 0 %start requeue buffer(b, b_next queue) %else enqueue buffer(b, b_next queue) %finish %finish %finish %end ! ARP stuff next... %routine ether start ARP receive %externalintegerspec ARP arrived %alias "ETHER__ARP_ARRIVED" %externalintegerspec ARP params %alias "ARP__PARAMS" %externalintegerspec ARP params size %alias "ARP__PARAMS_SIZE" %record(desc fm) d %record(IOSB fm) IOSB %record(buffer fm)%name buffer %integer status, resetting = 0 !! printstring("Ether start ARP receive"); newline buffer == claim buffer reset: status = QIO(ether ARP efn, ether ARP channel, IO readvblk, buffer_IOSB, addr(ARP arrived), addr(buffer), addr(buffer_data(0)), 96, 0, 0, addr(buffer_ether addrs), 0) %if status & 1 = 0 %start %signal 15, status %if resetting # 0; ! Failed tell network operator("Attempting to restart ARP ether channel...") d_l = ARP params size; d_a = addr(ARP params) status = QIOW(ether ARP efn, ether ARP channel, IO setmode ! IOM ctrl ! IOM startup, IOSB, 0, 0, 0, addr(d), 0, 0, 0, 0) %signal 15, status %if status & 1 = 0 %signal 15, IOSB_status %if IOSB_status & 1 = 0 resetting = 1 -> reset %finish %end %externalroutine ether ARP arrived %alias "ETHER__ARP_ARRIVED" %c (%record(buffer fm)%name ether ARP buffer) !! printstring("Ether ARP arrived: "); phex(addr(ether ARP buffer)); newline enqueue buffer(ether ARP buffer, ARP inbound queue) wake(0, 0) ether start ARP receive %end %routine ARP inbound(%record(buffer fm)%name b) %record(ARP fm) ARP %record(IOSB fm) IOSB %record(peer info fm)%name p %integer target, status, host, net, class %if b_IOSB_status & 1 = 0 %start tell network operator("ARP ether receive error " . itos(b_IOSB_status, 0)) sp_ARP errors in = sp_ARP errors in + 1 release buffer(b) %return %finish b_ARP packet == record(addr(b_data(0))) b_bytes = b_IOSB_length {N} net order short(b_ARP packet_format) {N} net order short(b_ARP packet_protocol) {N} net order short(b_ARP packet_op) {N} net order long(b_ARP packet_source protocol) {N} net order long(b_ARP packet_target protocol) %if b_ARP packet_format # ARP ether protocol %c %or b_ARP packet_protocol # ARP IP type %start !! printstring("Unrecognised ARP from ") !! print ether address(b_ether addrs_source) !! newline !! dump(byteinteger(addr(b_ARP packet)), b_IOSB_length) sp_ARP errors in = sp_ARP errors in + 1 release buffer(b) %return %finish %if b_ARP packet_source protocol = our address %start ! Someone impersonating us tell network operator("IP impersonator at " . %c ether address to S(b_ether addrs_source)) sp_ARP errors in = sp_ARP errors in + 1 release buffer(b) %return %finish sp_ARP in = sp_ARP in + 1 target = b_ARP packet_target protocol !! printstring("ARP inbound from ") !! print ether address(b_ARP packet_source hardware) !! printstring(", "); print inet address(b_ARP packet_source protocol) !! printstring(" for "); print inet address(b_ARP packet_target protocol) !! newline %if b_ARP packet_source protocol & 16_FF000000 = 0 %start ! Sun booting, throw it away release buffer(b) %return %finish p == find peer info(b_ARP packet_source protocol) p == new peer info(b_ARP packet_source protocol) %if p == nil %if p ## nil %start p_ARP in = p_ARP in + 1 %if b_ARP packet_op = ARP request code %start %if target = our address %start p_ARP for us = p_ARP for us + 1 ARP_format = ARP ether protocol ARP_protocol = ARP IP type ARP_hardware length = 6 ARP_protocol length = 4 ARP_op = ARP reply code ARP_source hardware = our ether address ARP_source protocol = our address ARP_target hardware = b_ether addrs_source ARP_target protocol = b_ARP packet_source protocol {N} net order short(ARP_format) {N} net order short(ARP_protocol) {N} net order short(ARP_op) {N} net order long(ARP_source protocol) {N} net order long(ARP_target protocol) sp_ARP responses = sp_ARP responses + 1 status = QIOW(ether TX efn, ether ARP channel, IO writevblk, IOSB, 0, 0, addr(ARP), 46, 0, 0, addr(b_ether addrs), 0) %if status & 1 = 0 %or IOSB_status & 1 = 0 %start sp_ARP errors out = sp_ARP errors out + 1 %finish %else ! Not for us split INet address(target, host, net, class) %if host = 0 %start p_ARP for old broadcast = p_ARP for old broadcast + 1 %else %if host = new broadcast mask(class) p_ARP for new broadcast = p_ARP for new broadcast + 1 %finish ! Else must be for someone else %finish %finish %if p_flags & peer ether address known = 0 %start p_ether address = b_ether addrs_source p_flags = p_flags ! peer ether address known %finish %finish release buffer(b) %end %owninteger ARP timer running = 0 %routine start ARP timer %externalintegerspec ARP timer %alias "INET__ARP_TIMER" %owninteger delta time = -10 000 000, t2 = -1 %integer status setAST(ASTs disabled) %if ARP timer running = 0 %start status = setimr(ARP timer efn, delta time, addr(ARP timer), addr(ARP timer)) %signal 15, status %if status & 1 = 0 ARP timer running = 1 %finish setAST(ASTs enabled) %end %externalroutine ARP timer %alias "INET__ARP_TIMER" %record(buffer fm)%name b ARP timer running = 0 %cycle b == dequeue buffer(ether pending ARP queue) %exit %if b == nil enqueue buffer(b, ether outbound queue) %repeat %end %routine start ether %externalintegerspec IP params %alias "IP__PARAMS" %externalintegerspec IP params size %alias "IP__PARAMS_SIZE" %externalintegerspec ARP params %alias "ARP__PARAMS" %externalintegerspec ARP params size %alias "ARP__PARAMS_SIZE" %bytearray char buffer(1 : char buffer size) %record(ether address fm) hardware address %record(peer info fm)%name broadcast peer %record(IOSB fm) IOSB %record(desc fm) d %integer status, i, j, pos %shortname x ether device = translate(ether device name) d_l = length(ether device); d_a = addr(ether device) + 1 status = assign(d, ether IP channel, 0, 0) %signal 15, status %if status & 1 = 0 d_l = IP params size; d_a = addr(IP params) status = QIOW(ether TX efn, ether IP channel, IO setmode ! IOM ctrl ! IOM startup, IOSB, 0, 0, 0, addr(d), 0, 0, 0, 0) %signal 15, status %if status & 1 = 0 %signal 15, IOSB_status %if IOSB_status & 1 = 0 d_l = char buffer size; d_a = addr(char buffer(1)) status = QIOW(ether TX efn, ether IP channel, IO sensemode ! IOM ctrl, IOSB, 0, 0, 0, addr(d), 0, 0, 0, 0) %signal 15, status %if status & 1 = 0 %signal 15, IOSB_status %if IOSB_status & 1 = 0 !! dump(char buffer(1), IOSB_length) ! Hunt for the physical and hardware addresses i = IOSB_length; pos = 1 %while i > 0 %cycle x == shortinteger(addr(char buffer(pos))) %if x & NMA pcli mask = NMA pcli hwa %start ! Found the hardware address hardware address_x(j) = char buffer(pos + 4 + j) %for j = 0, 1, 5 i = i - 10; pos = pos + 10 %else %if x & NMA pcli mask = NMA pcli pha ! Found the physical address our ether address_x(j) = char buffer(pos + 4 + j) %for j = 0, 1, 5 i = i - 10; pos = pos + 10 %else %if x & NMA pcli string = 0 ! Unwanted longword value i = i - 6; pos = pos + 6 %else ! Unwanted string value x == x ++ 1; ! -> Length word x = (x + 1) & (\ 1); ! Round to even size i = i - 4 - x; pos = pos + 4 + x %finish %repeat ! Finished with the IP channel, now go for the ARP channel d_l = length(ether device); d_a = addr(ether device) + 1 status = assign(d, ether ARP channel, 0, 0) %signal 15, status %if status & 1 = 0 d_l = ARP params size; d_a = addr(ARP params) status = QIOW(ether TX efn, ether ARP channel, IO setmode ! IOM ctrl ! IOM startup, IOSB, 0, 0, 0, addr(d), 0, 0, 0, 0) %signal 15, status %if status & 1 = 0 %signal 15, IOSB_status %if IOSB_status & 1 = 0 ether broadcast_x(i) = 16_FF %for i = 0, 1, 5 broadcast peer == new peer info(our network); !<<<<<<<<< broadcast peer_ether address = ether broadcast broadcast peer_flags = peer ether address known ether start IP receive ether start ARP receive pdate printstring("Ether started: "); printstring(ether device); space print ether address(our ether address) %unless same ether address(our ether address, hardware address) %start printstring(" (hardware "); print ether address(hardware address) print symbol(')') %finish newline %end %end %of %file