! BSD-style RIP process for Mouse INet, GDMR, Feb 1988. ! Revised Sept 1988 to only advertise particular routes to the "other" side. ! Although we're started up by the INet "main" module and are ! called by its clock handler, we're interface to UDP through the ! standard user interface. %option "-NonStandard-NoCheck-NoDiag-NoLine" %constinteger listener priority = 6 %constinteger listener size = 10240 %constinteger advertiser priority = 5 %constinteger advertiser size = 10240 %constinteger routed port = 520 %constinteger route slots = 32 %constinteger RIP limit = 250; !? %include "Moose:Mouse.Inc" %include "INet:INet.Inc" %include "INet:Stats.Inc" %include "INet:Control.Inc" %externalintegerspec control %externalrecord(INet statistics fm)%spec stats %constinteger routed light = 16_80000000 %constinteger infinity = 16_7FFFFFFF %externalintegerspec slow IP address %externalintegerspec ether IP address %externalroutinespec set ether IP address(%integer example) %externalpredicatespec FS lookup(%string(31) what, %integername value) %externalroutinespec FS insert(%string(31) what, %integer value) %systemroutinespec phex(%integer x) %recordformat RIP entry fm(%short type, %short spare1, %integer network, %integer spare2, spare3, %integer metric) %constinteger RIP entry size = 2 + 2 + 4 + 8 + 4 %recordformat RIP packet fm(%byte op, version, %short spare, %record(RIP entry fm)%array e(1 : RIP limit)) %routine print INet address(%integer addr) write(addr >> 24 & 255, 0); print symbol('.') write(addr >> 16 & 255, 0); print symbol('.') write(addr >> 8 & 255, 0); print symbol('.') write(addr & 255, 0) %end ! Route tables & manipulation thereof %constinteger unreachable = 16 %constinteger dead = 16_10000000 %constinteger alive interval = 6; ! Ticks %constinteger forget interval = 12; ! Ticks %owninteger stamp = 0 %recordformat route fm(%integer network, mask, gateway, metric, stamp, via) %ownrecord(route fm)%array route table(1 : route slots) = 0(*) %owninteger routes = 0 %owninteger local routes = 0 %ownrecord(semaphore fm) route semaphore = 0 %externalroutine find route(%integer target, %integername gate, via) %record(route fm)%name r %integer i !! printstring("Find route for "); print INet address(target); newline semaphore wait(route semaphore) ! We know there must always be one route, as otherwise we wouldn't ! be able to speak to anyone.... %for i = 1, 1, routes %cycle r == route table(i) %if target & r_mask = r_network %and r_metric < unreachable %start ! Found a route gate = r_gateway via = r_via signal semaphore(route semaphore) !! printstring("Found: -> "); print INet address(r_gateway); newline %return %finish %repeat signal semaphore(route semaphore) !! printstring("Unknown"); newline gate = -1; ! Unknown %end %externalroutine add local route(%integer address, metric, via) %record(route fm)%name r %integer i !! printstring("Add local route: "); print INet address(address) !! printstring(" metric "); write(metric, 0); newline semaphore wait(route semaphore) ! Add the route at the end of our tables r == route table(routes + 1) %if address & 16_80000000 = 0 %start ! Class A r_mask = 16_FF000000 %else %if address & 16_C0000000 = 16_80000000 ! Class B r_mask = 16_FFFF0000 %else %if address & 16_E0000000 = 16_C0000000 ! Class C r_mask = 16_FFFFFF00 %else ! Unknown -- ignore it signal semaphore(route semaphore) %return %finish r_network = address & r_mask r_gateway = 0; ! -> direct r_metric = metric r_stamp = infinity r_via = via routes = routes + 1 local routes = local routes + 1 signal semaphore(route semaphore) stats_RIP updated = stats_RIP updated + 1 %end %routine add route(%integer network, gateway, metric, via) %record(route fm)%name r %integer i, mask %if control & trace RIP in # 0 %start printstring(" To: "); print INet address(network) printstring(" via "); print INet address(gateway) printstring(" metric "); write(metric, 0) printstring(" from ") %if via = 1 %then printstring("slow") %else printstring("fast") newline %finish %return %if network = 0 %or metric >= unreachable %if network & 16_80000000 = 0 %start ! Class A mask = 16_FF000000 %else %if network & 16_C0000000 = 16_80000000 ! Class B mask = 16_FFFF0000 %else %if network & 16_E0000000 = 16_C0000000 ! Class C mask = 16_FFFFFF00 %else ! Unknown -- ignore it %return %finish network = network & mask semaphore wait(route semaphore) ! First find out if it's there already %for i = 1, 1, routes %cycle r == route table(i) %if r_network = network %start ! Found it !! printstring("Slot "); write(i, 0) !! printstring(" -> "); print INet address(r_gateway) !! printstring(" metric "); write(r_metric, 0); newline %if gateway = r_gateway %or metric < r_metric %start ! Metric update from the gateway, or a better route. ! Track it, and tally it if it's a genuine update. stats_RIP updated = stats_RIP updated + 1 %if metric # r_metric r_gateway = gateway r_metric = metric r_stamp = stamp r_via = via %finish ! Nothing (more) to do signal semaphore(route semaphore) %return %finish %repeat ! If we get here we haven't found the entry. For convenience ! we'll add it at the end of our tables meantime.... r == route table(routes + 1) r_network = network r_mask = mask r_gateway = gateway r_metric = metric r_stamp = stamp r_via = via routes = routes + 1 signal semaphore(route semaphore) stats_RIP updated = stats_RIP updated + 1 %end ! UDP comms stuff %ownrecord(mailbox fm)%name request box %ownrecord(semaphore fm) RX semaphore = 0 %ownrecord(mailbox fm) RX mailbox = 0 %ownrecord(INet user request fm) RX request = 0 %owninteger RX unit = 0 %ownrecord(semaphore fm) TX semaphore = 0 %ownrecord(mailbox fm) TX mailbox = 0 %ownrecord(INet user request fm) TX request = 0 %owninteger TX unit = 0 %ownrecord(semaphore fm) advertiser semaphore = 0 %recordformat connect fm(%integer ra, rp, lp) ! Peer daemon listener %routine listener process %owninteger first time = 0 %record(connect fm) c %record(RIP packet fm) p %record(INet user request fm)%name reply %integer i, n open input(2, ":N"); select input(2) open output(2, ":T"); select output(2) ! Attach ourselves to the routed UDP port RX request_key = addr(RX request) RX request_code = UDP allocate unit request send message(RX request, request box, RX mailbox) reply == receive message(RX mailbox) %if reply ## RX request %start printstring("Dubious UDP reply (allocate)"); newline %stop %else %if reply_status # 0 printstring("UDP reply (allocate): "); write(reply_status, 0) newline %stop %finish !! printstring("Routed RX unit "); write(reply_unit, 0); newline RX unit = reply_unit ! Define UDP context c_ra = 0; c_rp = 0 c_lp = routed port RX request_unit = RX unit RX request_key = addr(RX request) RX request_code = UDP define context request RX request_buffer == byteinteger(addr(c)) RX request_bytes = 12 send message(RX request, request box, RX mailbox) reply == receive message(RX mailbox) %if reply ## RX request %start printstring("Dubious UDP reply (allocate)"); newline %stop %else %if reply_status # 0 printstring("UDP reply (allocate): "); write(reply_status, 0) newline %stop %finish !! printstring("Context defined: "); print INet address(c_ra) !! space; write(c_rp, 0); space; write(c_lp, 0); newline %cycle ! Loop, reading RIP packets. RX request_unit = RX unit RX request_key = addr(RX request) RX request_code = UDP receive request RX request_timeout = 0; ! None RX request_buffer == byteinteger(addr(p)) send message(RX request, request box, RX mailbox) reply == receive message(RX mailbox) !L! lights or A(routed light) %if reply ## RX request %start printstring("Dubious UDP reply (receive)"); newline %stop %else %if reply_status # 0 printstring("UDP reply (receive): "); write(reply_status, 0) newline %stop %else %if p_op = 2 %and p_version = 1 stats_RIP packets in = stats_RIP packets in + 1 %if first time = 0 %and reply_interface = 2 %start ! First message from the fast ether, so set our IP address set ether IP address(reply_peer) first time = 1 %finish n = (reply_bytes - 4) // RIP entry size %if control & trace RIP in # 0 %start printstring("RIP from "); print INet address(reply_peer) write(n, 3); printstring(" entries via ") %if reply_interface = 1 %then printstring("slow") %c %else printstring("fast") newline %finish %for i = 1, 1, n %cycle add route(p_e(i)_network, reply_peer, %c p_e(i)_metric + 1, reply_interface) %c %if p_e(i)_type = 2 %repeat %finish !L! lights and A(\ routed light) %repeat %end ! Route advertiser %routine advertise to(%integer address, n, %record(RIP packet fm)%name p) %record(INet user request fm)%name reply %record(connect fm) c %return %if address = 0 ! Define UDP context c_ra = address c_rp = routed port ! 16_20000; ! Outbound only c_lp = routed port !! printstring("Defining context: "); phex(c_ra) !! space; phex(c_rp); space; phex(c_lp); newline TX request_unit = TX unit TX request_key = addr(TX request) TX request_code = UDP define context request TX request_buffer == byteinteger(addr(c)) TX request_bytes = 12 send message(TX request, request box, TX mailbox) reply == receive message(TX mailbox) %if reply ## TX request %start printstring("Dubious UDP reply (define)"); newline %return %else %if reply_status # 0 printstring("UDP reply (define): "); write(reply_status, 0) newline %return %finish !! printstring("Context defined: "); print INet address(c_ra) !! space; write(c_rp, 0); space; write(c_lp, 0); newline TX request_unit = TX unit TX request_key = addr(TX request) TX request_code = UDP data request TX request_buffer == byteinteger(addr(p)) TX request_bytes = n * RIP entry size + 4 send message(TX request, request box, TX mailbox) reply == receive message(TX mailbox) %if reply ## TX request %start printstring("Dubious UDP reply (send)"); newline %return %else %if reply_status # 0 printstring("UDP reply (send): "); write(reply_status, 0) newline %return %finish !! printstring("Sent RIP to "); print INet address(address); newline stats_RIP packets out = stats_RIP packets out + 1 %end %routine advertiser process %record(RIP packet fm) p %record(RIP entry fm)%name e %record(route fm)%name r %record(INet user request fm)%name reply %integer i, n, x open input(2, ":N"); select input(2) open output(2, ":T"); select output(2) ! Get ourselves a UDP unit TX request_key = addr(TX request) TX request_code = UDP allocate unit request send message(TX request, request box, TX mailbox) reply == receive message(TX mailbox) %if reply ## TX request %start printstring("Dubious UDP reply (allocate)"); newline %stop %else %if reply_status # 0 printstring("UDP reply (allocate): "); write(reply_status, 0) newline %stop %finish !! printstring("Routed TX unit "); write(reply_unit, 0); newline TX unit = reply_unit %cycle semaphore wait(advertiser semaphore) !L! lights or B(routed light) %for x = 1, 1, local routes %cycle ! Create a RIP packet p = 0; n = 0 p_op = 2; p_version = 1 semaphore wait(route semaphore) %for i = 1, 1, routes %cycle r == route table(i) %if r_via # x %and r_metric <= unreachable %start n = n + 1 e == p_e(n) e_type = 2; e_network = r_network e_metric = r_metric !? e_metric = e_metric + 1 %if x = 1; ! Slug the slow ether %if control & trace RIP out # 0 %start printstring("Advertising "); print INet address(e_network) printstring(" metric "); write(e_metric, 0) printstring(" to ") %if x = 1 %then printstring("slow") %else printstring("fast") newline %finish %finish %repeat signal semaphore(route semaphore) ! Now send it on its way %if n > 0 %start %if x = 1 %start advertise to((slow IP address & 16_FFFFFF00) ! 255, n, p) %else advertise to(ether IP address & 16_FFFF0000, n, p) %finish %finish %repeat !L! lights and B(\ routed light) %repeat %end ! Clock, initialisation %externalroutine routed clock %record(route fm)%name r %integer i, d stamp = stamp + 1 semaphore wait(route semaphore) %for i = 1, 1, routes %cycle r == route table(i) d = stamp - r_stamp %if d >= forget interval %start r_metric = dead !stats_RIP dropped = stats_RIP dropped + 1 %else %if d >= alive interval r_metric = unreachable stats_RIP dropped = stats_RIP dropped + 1 %finish %repeat signal semaphore(route semaphore) signal semaphore(advertiser semaphore) %c %if stamp & 1 # 0 %and local routes > 1 %and control & hush RIP = 0 %end %externalroutine start routed %record(process fm)%name p %integer x %label listener, advertiser %if FS lookup(INet mailbox name, x) %start request box == record(x) %else printstring("Routed: no INet mailbox??"); newline %stop %finish setup semaphore(RX semaphore) setup mailbox(RX mailbox, RX semaphore) setup message(RX request, size of(RX request)) setup semaphore(TX semaphore) setup mailbox(TX mailbox, TX semaphore) setup message(TX request, size of(TX request)) setup semaphore(advertiser semaphore) setup semaphore(route semaphore) signal semaphore(route semaphore) FS insert("INET_ROUTE_TABLE", addr(route table(1))) p == create process(listener size, addr(listener), listener priority, nil) p == create process(advertiser size, addr(advertiser), advertiser priority, nil) !! printstring("Routed started"); newline %return listener: listener process advertiser: advertiser process %end %end %of %file