! UDP module for INet process, GDMR, Feb/March 1987 ! Ignore the checksum on input and don't generate one on output ! (4.2 BSD gets it wrong). %constinteger wild UDP port flag = 16_00010000 %constinteger UDP port mask = 16_0000FFFF %constinteger UDP privileged limit = 1024 %record(UDP entry fm)%map find UDP entry(%integer remote address, remote port, %integer local port) ! Try for an exact match if possible. If not, try for a wild match. %record(UDP entry fm)%name t, possible == nil %integer i %for i = 1, 1, max UDP %cycle t == UDP table_UDP(i) !! printstring("Trying "); print inet address(t_remote address) !! write(t_remote port, 1); write(t_local port, 1); newline %if t_local port = local port %start %result == t %if t_remote address = remote address %c %and (t_remote port = remote port %c %or t_remote port & wild UDP port flag # 0) possible == t %if t_remote address = 0 %finish %repeat %if possible ## nil %and possible_slot = 0 %start ! We've matched on an unused slot?? pdate printstring("UDP match for unused slot??"); newline spaces(24); phex(remote address); space; phex(remote port) space; phex(local port); newline spaces(24); phex(possible_remote address); space phex(possible_remote port); space phex(possible_local port); newline %result == nil %finish %result == possible %end %routine UDP inbound(%record(buffer fm)%name b) %integer c, host, net, class %if b_UDP header_checksum = 0 %start !! printstring("No UDP checksum"); newline b_p_UDP no checksums = b_p_UDP no checksums + 1 %if b_p ## nil %else c = calculate pseudo checksum(b_UDP header, b_IP bytes, b_IP header_source, b_IP header_destination, IP UDP protocol, b_IP bytes) %if 0 # c # 16_FFFF %start !! printstring("UDP checksum error "); phex(c); newline c = calculate pseudo checksum(b_UDP header, b_IP bytes, b_IP header_source, b_IP header_destination, IP UDP protocol, b_UDP header_length) %if c = 0 %or c = 16_FFFF %start !! printstring("Bogus UDP checksum "); phex(c); newline b_p_UDP bogus checksums = b_p_UDP bogus checksums + 1 %if b_p ## nil %else !! printstring("UDP checksum error "); phex(c); newline b_p_UDP checksum errors = b_p_UDP checksum errors + 1 %if b_p ## nil %finish %finish %finish {N} net order short(b_UDP header_source) {N} net order short(b_UDP header_destination) {N} net order short(b_UDP header_length) {N} net order short(b_UDP header_checksum) %if b_UDP header_length # b_IP bytes %start ! Length wrong pdate printstring("UDP length error from ") print inet address(b_IP header_source) printstring(": UDP length "); write(b_UDP header_length, 0) printstring(", IP length "); write(b_IP bytes, 0); newline b_p_UDP other errors = b_p_UDP other errors + 1 %if b_p ## nil release buffer(b) %return %finish b_data start == byteinteger(addr(b_UDP header) + 8) b_data bytes = b_UDP header_length - 8 b_p_UDP packets in = b_p_UDP packets in + 1 b_p_UDP bytes in = b_p_UDP bytes in + b_data bytes !! printstring("UDP inbound from ") !! print inet address(b_IP header_source) !! printstring(" port "); write(b_UDP header_source, 0) !! printstring(" for port "); write(b_UDP header_destination, 0) !! printstring(", data size "); write(b_data bytes, 0) !! newline !! dump(b_data start, b_data bytes) b_UDP entry == find UDP entry(b_IP peer, b_UDP header_source, b_UDP header_destination) %if b_UDP entry == nil %start ! No-one there to receive it !! printstring("UDP: no recipient"); newline release buffer(b) %else ! Send it to the port's owner !! printstring("Sending UDP to "); write(b_UDP entry_slot, 0); newline %if b_UDP entry_remote address = 0 %start ! Wild context. Should we convert it? split INet address(b_IP header_destination, host, net, class) %if 0 # host # new broadcast mask(class) %start ! Not a broadcast b_UDP entry_remote address = b_IP peer b_UDP entry_remote port = b_UDP header_source b_UDP entry_peer info == b_p !! printstring("Wild UDP context converted to ") !! print inet address(b_IP peer); print symbol('.') !! write(b_UDP header_source, 0); newline %finish %else %if b_UDP entry_remote port & wild UDP port flag # 0 b_UDP entry_remote port = b_UDP header_source !! printstring("Wild remote port converted to ") !! write(b_UDP entry_remote port, 0); newline %finish UDP send to user(b) %finish %end %routine UDP outbound(%record(buffer fm)%name b) %owninteger UDP last privileged = UDP privileged limit %owninteger UDP last unprivileged = UDP privileged limit %switch op(UDP define context request - 1 : UDP claim priv request) %recordformat connect fm(%integer remote address, remote port, local port) %record(connect fm)%name connect %record(peer info fm)%name p %integer i, which !! printstring("UDP outbound"); newline -> op(b_code) %if UDP interpret user request(b) !! printstring("Dud request from "); write(b_UDP entry_slot, 0); newline release buffer(b) %return op(UDP define context request): connect == record(addr(b_data start)) !! printstring("Define context from "); write(b_UDP entry_slot, 0) !! printstring(": "); print INet address(connect_remote address) !! space; write(connect_remote port & UDP port mask, 0) !! space; write(connect_local port, 0) !! printstring(", flags "); phex(connect_remote port & 16_FFFF0000) !! newline %if b_privilege = 0 %and %c (connect_local port <= UDP privileged limit %or %c connect_remote address = 0) %start UDP open response(b_UDP entry_slot, privilege error, 0, 0, 0) release buffer(b) %return %finish %if connect_remote address = 0 %start ! Wild, map on to broadcast record p == find peer info(our network) %else ! Specific host p == find peer info(connect_remote address) p == new peer info(connect_remote address) %if p == nil %finish %if p == nil %start ! Still unknown UDP open response(b_UDP entry_slot, reset error, 0, 0, 0) release buffer(b) %return %finish b_UDP entry_remote address = connect_remote address b_UDP entry_remote port = connect_remote port b_UDP entry_local port = connect_local port b_UDP entry_peer info == p op(UDP query context request): !! printstring("Responding with defined context"); newline UDP open response(b_UDP entry_slot, 0, b_UDP entry_remote address, b_UDP entry_remote port, b_UDP entry_local port) release buffer(b) %return op(UDP forget context request): UDP disable(b_UDP entry_slot, 0) UDP enable(b_UDP entry_slot) b_UDP entry = 0 release buffer(b) %return op(UDP data request): !! printstring("Send to "); print INet address(b_UDP entry_remote address) !! space; write(b_UDP entry_remote port & UDP port mask, 0) !! space; write(b_UDP entry_local port, 0); newline %if b_UDP entry_local port = 0 %or b_UDP entry_remote port = 0 %start ! Undefined address -- dump it silently. Note that this may arise ! through a race condition between client and server.... release buffer(b) %return %finish b_IP peer = b_UDP entry_remote address b_IP peer = our network %if b_IP peer = 0; ! Broadcast <<<<<<<< b_IP bytes = b_data bytes + 8 b_protocol = IP UDP protocol b_p == b_UDP entry_peer info b_p_UDP packets out = b_p_UDP packets out + 1 b_p_UDP bytes out = b_p_UDP bytes out + b_data bytes b_UDP header == record(addr(b_data start) - 8) b_UDP header_source = b_UDP entry_local port b_UDP header_destination = b_UDP entry_remote port & UDP port mask b_UDP header_length = b_IP bytes b_UDP header_checksum = 0; ! i.e. none sent !! dump(byteinteger(addr(b_UDP header)), b_IP bytes) {N} net order short(b_UDP header_source) {N} net order short(b_UDP header_destination) {N} net order short(b_UDP header_length) {N} ! Checksum is zero, so same either way round enqueue buffer(b, IP outbound queue) %return op(UDP claim request): op(UDP claim priv request): !! printstring("Claim port request from ") !! write(b_UDP entry_slot, 0); newline try claim port again: %if b_code = UDP claim priv request %start %if b_privilege = 0 %start UDP claim response(b_UDP entry_slot, privilege error, 0) release buffer(b) %return %finish UDP last privileged = UDP last privileged - 1 UDP last privileged = 1023 %if UDP last privileged < 768 which = UDP last privileged !! printstring("Looking for privileged, trying ") !! write(which, 0); newline %else UDP last unprivileged = UDP last unprivileged + 1 UDP last unprivileged = 1025 %if UDP last unprivileged > 2048 which = UDP last unprivileged !! printstring("Looking for unprivileged, trying ") !! write(which, 0); newline %finish %for i = 1, 1, max UDP %cycle -> try claim port again %if UDP table_UDP(i)_local port = which %repeat ! If we fall through here then the port was free... !! printstring("Allocated "); write(which, 0); newline UDP claim response(b_UDP entry_slot, 0, which) release buffer(b) %end %end %of %file