udp.c is the interace for the udp protocol.

     1  /*
     2  udp.c
       
     3  Copyright 1995 Philip Homburg
     4  */
       
     5  #include "inet.h"
     6  #include "type.h"
       
     7  #include "assert.h"
     8  #include "buf.h"
     9  #include "clock.h"
    10  #include "icmp_lib.h"
    11  #include "io.h"
    12  #include "ip.h"
    13  #include "sr.h"
    14  #include "udp.h"
       
    15  THIS_FILE
       

UDP_FD_NR is the size of the udp fd table udp_fd_table.

    16  #define UDP_FD_NR               32

Used to calculate hash value for the up_port_hash table in the udp_port_t structure.

    17  #define UDP_PORT_HASH_NR        16              /* Must be a power of 2 */
       

udp_port is the data structure which holds information about the the udp interface
to the network interface. There is a 1-1 relationship between the udp_port elements
and the network interfaces.

    18  typedef struct udp_port
    19  {

up_flags, up_state: state of port table element.

    20          int up_flags;
    21          int up_state;

up_ipfd: index in to fd table of ip protocol.

    22          int up_ipfd;

up_minor: corresponding minor device number.

    23          int up_minor;

up_ipdev: index in to port table of ip interface.

    24          int up_ipdev;

up_wr_pack: packet to write.

    25          acc_t *up_wr_pack;

up_ipaddr: ip address if the ip address is set for the associated ip device/interface.

    26          ipaddr_t up_ipaddr;

up_next_fd: first element in the fd table to tries to send when inet tries to send all
unsent packets in the function restart_write_port.

    27          struct udp_fd *up_next_fd;

up_write_fd: current element in the fd table which inet is trying to write for udp.

    28          struct udp_fd *up_write_fd;

up_port_any: head of linked list of fds which receive messages on any local port.

    29          struct udp_fd *up_port_any;

udp_fd: hash table of fds which receive messages on a particular local port.

    30          struct udp_fd *up_port_hash[UDP_PORT_HASH_NR];
    31  } udp_port_t;
       
    32  #define UPF_EMPTY       0x0
    33  #define UPF_WRITE_IP    0x1
    34  #define UPF_WRITE_SP    0x2
    35  #define UPF_READ_IP     0x4
    36  #define UPF_READ_SP     0x8
    37  #define UPF_SUSPEND     0x10
    38  #define UPF_MORE2WRITE  0x20
       

Used in the field up_state in udp_port.
UPS_EMPTY = before any configuration of channel.

    39  #define UPS_EMPTY       0

UPS_SETPROTO = Beginning configuration of ip channel.

    40  #define UPS_SETPROTO    1

UPS_GETCONF = IP Channel has been configured using the NWIOSIPOPT ioctl call for the ip device.

    41  #define UPS_GETCONF     2

UPS_MAIN = IP Channel has reported the ip address of the channel to the upd interface. udp channel has been configured.

    42  #define UPS_MAIN        3

UPS_ERROR = Error has occurred.

    43  #define UPS_ERROR       4
       
    44  typedef struct udp_fd
    45  {

uf_flags: state of fd table element.

    46          int uf_flags;

uf_port: points to the port table entry in udp_port_table used by fd.
2 udp channels (ie elements in the udp_fd_table) have the same uf_port if and
only if they are channels for the same network interface. This is done for
the following reason. The IP interface can only look at the ip header in
determining where else to send a particular messsage to after it has processed
it. The IP header tells what lower level protocol (ie TCP/IP, UDP/IP, etc.) the
message is using ie it can not look at the local port number. Hence the IP interface
sends the message to the interface which implements the lower level protocol. The
udp_port_t structure is the structure which the ip interface sends the message to
because it relates the udp interface to the ip interface.

    47          udp_port_t *uf_port;

uf_ioreq: current ioctl request.
ioreq_t is type-defined as an int in inet/inet.h.

    48          ioreq_t uf_ioreq;

uf_srfd: index to sr_fd_table in sr.c ie index for channel.

    49          int uf_srfd;

struct nwio_udpopt is defined in include/net/gen/udp_io.h


typedef struct nwio_udpopt
{
          unsigned long nwuo_flags;
          udpport_t nwuo_locport;
          udpport_t nwuo_remport;
          ipaddr_t nwuo_locaddr;
          ipaddr_t nwuo_remaddr;
} nwio_udpopt_t;

nwuo_locport is the local port.
nwuo_remport is the remote port.
nwuo_locaddr is the local address.
nwuo_remaddr is the remote address.

    50          nwio_udpopt_t uf_udpopt;

uf_get_userdata: pointer to sr_get_userdata in sr.c.

    51          get_userdata_t uf_get_userdata;

uf_put_userdata: pointer to sr_put_userdata in sr.c.

    52          put_userdata_t uf_put_userdata;

uf_rdbuf_head: head of queue of received packets which are waiting to be read.
Next pointer for queue is the acc_ext_link field for the acc_t accessor structure.

    53          acc_t *uf_rdbuf_head;

uf_rdbuf_tail: tail of queue to received packets which are waiting to be read.
Next pointer for queue is the acc_ext_link field for the acc_t accessor structure.

    54          acc_t *uf_rdbuf_tail;

uf_rd_count: set in the read system call. Declares how many bytes to be read to buffer.

    55          size_t uf_rd_count;

uf_wr_count: set in the write system call. Declares how many bytes to be written from buffer.

    56          size_t uf_wr_count;

uf_exp_tim: expiration time of packet. If the expiration time is before time that packet is read, the packet is dumped and not read.

    57          time_t uf_exp_tim;

uf_port_next: next pointer in linked list or hashtable of currently used port table entries.

    58          struct udp_fd *uf_port_next;
    59  } udp_fd_t;
       
    60  #define UFF_EMPTY       0x0
    61  #define UFF_INUSE       0x1
    62  #define UFF_IOCTL_IP    0x2
    63  #define UFF_READ_IP     0x4
    64  #define UFF_WRITE_IP    0x8
    65  #define UFF_OPTSET      0x10
       
    66  FORWARD void read_ip_packets ARGS(( udp_port_t *udp_port ));
    67  FORWARD void udp_buffree ARGS(( int priority ));
    68  #ifdef BUF_CONSISTENCY_CHECK
    69  FORWARD void udp_bufcheck ARGS(( void ));
    70  #endif
    71  FORWARD void udp_main ARGS(( udp_port_t *udp_port ));
    72  FORWARD acc_t *udp_get_data ARGS(( int fd, size_t offset, size_t count,
    73          int for_ioctl ));
    74  FORWARD int udp_put_data ARGS(( int fd, size_t offset, acc_t *data,    
    75          int for_ioctl ));
    76  FORWARD void udp_restart_write_port ARGS(( udp_port_t *udp_port ));
    77  FORWARD void udp_ip_arrived ARGS(( int port, acc_t *pack, size_t pack_size ));
    78  FORWARD void reply_thr_put ARGS(( udp_fd_t *udp_fd, int reply,
    79          int for_ioctl ));
    80  FORWARD void reply_thr_get ARGS(( udp_fd_t *udp_fd, int reply,
    81          int for_ioctl ));
    82  FORWARD int udp_setopt ARGS(( udp_fd_t *udp_fd ));
    83  FORWARD udpport_t find_unused_port ARGS(( int fd ));
    84  FORWARD int is_unused_port ARGS(( Udpport_t port ));
    85  FORWARD int udp_packet2user ARGS(( udp_fd_t *udp_fd ));
    86  FORWARD void restart_write_fd ARGS(( udp_fd_t *udp_fd ));
    87  FORWARD u16_t pack_oneCsum ARGS(( acc_t *pack ));
    88  FORWARD void udp_rd_enqueue ARGS(( udp_fd_t *udp_fd, acc_t *pack,
    89                                                          time_t exp_tim ));
    90  FORWARD void hash_fd ARGS(( udp_fd_t *udp_fd ));
    91  FORWARD void unhash_fd ARGS(( udp_fd_t *udp_fd ));
       
    92  PRIVATE udp_port_t udp_port_table[UDP_PORT_NR];
    93  PRIVATE udp_fd_t udp_fd_table[UDP_FD_NR];
       

udp_init(): does initialization. Initializes udp port tables so that uc_minor
is the appropriate minor device number and uc_port is the index to the appropriate
ip port table entry (ie network interface). It calls sr_add_minor to add itself
with the appropriate minor device number in to the sr fd table. sr_add_minor
sets the fields of the sr_fd structure to the udp specific values and functions
except for the fields srf_flags and srf_port. srf_flags is used to store the
state of the sr_fd structure. It also calls udp_main to do some intialization.
When udp_main is called in udp_init, udp_port->up_state is UPS_EMPTY.

    94  PUBLIC void udp_init()
    95  {
    96          udp_fd_t *udp_fd;
    97          udp_port_t *udp_port;
    98          int i, j, result;
       
    99          assert (BUF_S >= sizeof(struct nwio_ipopt));
   100          assert (BUF_S >= sizeof(struct nwio_ipconf));
   101          assert (BUF_S >= sizeof(struct nwio_udpopt));
   102          assert (BUF_S >= sizeof(struct udp_io_hdr));
   103          assert (UDP_HDR_SIZE == sizeof(udp_hdr_t));
   104          assert (UDP_IO_HDR_SIZE == sizeof(udp_io_hdr_t));
       
   105  #if ZERO
   106          for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
   107          {
   108                  udp_fd->uf_flags= UFF_EMPTY;
   109                  udp_fd->uf_rdbuf_head= NULL;
   110          }
   111  #endif
       

Set udp_buffree to be the function to call when freeing accessor in buf.c.

   112  #ifndef BUF_CONSISTENCY_CHECK
   113          bf_logon(udp_buffree);
   114  #else
   115          bf_logon(udp_buffree, udp_bufcheck);
   116  #endif
       
   117          for (i= 0, udp_port= udp_port_table; i<UDP_PORT_NR; i++, udp_port++)
   118          {

Set up_minor to the minor device number.

   119                  udp_port->up_minor= udp_conf[i].uc_minor;

Set up_ipdev to the index to the ip port table.

   120                  udp_port->up_ipdev= udp_conf[i].uc_port;
       
   121  #if ZERO
   122                  udp_port->up_flags= UPF_EMPTY;
   123                  udp_port->up_state= UPS_EMPTY;
   124  #endif
   125                  udp_port->up_next_fd= udp_fd_table;
   126  #if ZERO
   127                  udp_port->up_write_fd= NULL;
   128                  udp_port->up_port_any= NULL;
   129                  for (j= 0; j<UDP_PORT_HASH_NR; j++)
   130                          udp_port->up_port_hash[j]= NULL;
   131  #endif
       

Add to sr_fd_table.

   132                  result= sr_add_minor (udp_port->up_minor,
   133                          udp_port-udp_port_table, udp_open, udp_close, udp_read,
   134                          udp_write, udp_ioctl, udp_cancel);
   135                  assert (result >= 0);
       

Perform initialization with up_state = UPS_EMPTY.

   136                  udp_main(udp_port);
   137          }
   138  }
       

udp_main performs initialization routines depending on the state the udp is in
as determined by up_state.

   139  PRIVATE void udp_main(udp_port)
   140  udp_port_t *udp_port;
   141  {
   142          udp_fd_t *udp_fd;
   143          int result, i;
       
   144          switch (udp_port->up_state)
   145          {

UPS_EMPTY = before any configuration of channel.

   146          case UPS_EMPTY:

UPS_SETPROTO = Beginning configuration of ip channel.

   147                  udp_port->up_state= UPS_SETPROTO;
       

get index to ip channel array.
udp_put_data returns data specific to the udp port table (eg ip errors and ip ioctl calls).
udp_ip_arrived returns data specific to a udp fd table (eg read calls).

   148                  udp_port->up_ipfd= ip_open(udp_port->up_ipdev,
   149                          udp_port-udp_port_table, udp_get_data, udp_put_data,
   150                          udp_ip_arrived);
   151                  if (udp_port->up_ipfd < 0)
   152                  {
   153                          udp_port->up_state= UPS_ERROR;
   154                          DBLOCK(1, printf("%s, %d: unable to open ip port\n",
   155                                  __FILE__, __LINE__));
   156                          return;
   157                  }
       

Configure ip channel by using the NWIOSIPOPT ioctl.

   158                  result= ip_ioctl(udp_port->up_ipfd, NWIOSIPOPT);

Configuration could not be completed if result == NW_SUSPEND. Suspend until
the NWIOSIPOPT ioctl call can be completed.

   159                  if (result == NW_SUSPEND)
   160                          udp_port->up_flags |= UPF_SUSPEND;
   161                  if (result<0)
   162                  {
   163                          return;
   164                  }

If configuration of ip channel could be completed sucessfully udp_port->up_state
should have been changed to UPS_GETCONF.

   165                  if (udp_port->up_state != UPS_GETCONF)
   166                          return;
   167                  /* drops through */

UPS_GETCONF = IP Channel has been configured using the NWIOSIPOPT ioctl call for the ip device.

   168          case UPS_GETCONF:

Unsuspend the udp port.

   169                  udp_port->up_flags &= ~UPF_SUSPEND;
       

Get network address of network interface

   170                  result= ip_ioctl(udp_port->up_ipfd, NWIOGIPCONF);

Getting network address could not be completed if result == NW_SUSPEND. Suspend until
the NWIOGIPCONF ioctl call can be completed.

   171                  if (result == NW_SUSPEND)
   172                          udp_port->up_flags |= UPF_SUSPEND;
   173                  if (result<0)
   174                  {
   175                          return;
   176                  }

If getting network address could be completed sucessfully udp_port->up_state
should have been changed to UPS_MAIN.

   177                  if (udp_port->up_state != UPS_MAIN)
   178                          return;
   179                  /* drops through */

UPS_MAIN = IP Channel has reported the ip address of the channel to the upd interface. udp channel has been configured.

   180          case UPS_MAIN:

Unsuspend the udp port.

   181                  udp_port->up_flags &= ~UPF_SUSPEND;
       

Look for any fds in the udp_fd_table array which are using the network interface.

   182                  for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
   183                  {
   184                          if (!(udp_fd->uf_flags & UFF_INUSE))
   185                                  continue;
   186                          if (udp_fd->uf_port != udp_port)
   187                                  continue;

Run any ioctl calls which have been suspended.

   188                          if (udp_fd->uf_flags & UFF_IOCTL_IP)
   189                                  udp_ioctl(i, udp_fd->uf_ioreq);
   190                  }

Read any ip packets which have been received.

   191                  read_ip_packets(udp_port);
   192                  return;
   193          default:
   194                  DBLOCK(1, printf("udp_port_table[%d].up_state= %d\n",
   195                          udp_port-udp_port_table, udp_port->up_state));
   196                  ip_panic(( "unknown state" ));
   197                  break;
   198          }
   199  }
       

Implements the open system call on a udp device.
udp_open returns an index in to the udp fd table for the udp/ip channel.

   200  int udp_open (port, srfd, get_userdata, put_userdata, put_pkt)
   201  int port;
   202  int srfd;
   203  get_userdata_t get_userdata;
   204  put_userdata_t put_userdata;
   205  put_pkt_t put_pkt;
   206  {
   207          int i;
   208          udp_fd_t *udp_fd;
       
   209          for (i= 0; i<UDP_FD_NR && (udp_fd_table[i].uf_flags & UFF_INUSE);
   210                  i++);
       
   211          if (i>= UDP_FD_NR)
   212          {
   213                  DBLOCK(1, printf("out of fds\n"));
   214                  return EOUTOFBUFS;
   215          }
       
   216          udp_fd= &udp_fd_table[i];
       

Marks a upd fd as used.

   217          udp_fd->uf_flags= UFF_INUSE;
   218          udp_fd->uf_port= &udp_port_table[port];
   219          udp_fd->uf_srfd= srfd;
   220          udp_fd->uf_udpopt.nwuo_flags= UDP_DEF_OPT;

Sets the appropriate functions to get and put messages from and to a sr channel.

   221          udp_fd->uf_get_userdata= get_userdata;
   222          udp_fd->uf_put_userdata= put_userdata;
   223          assert(udp_fd->uf_rdbuf_head == NULL);
   224          udp_fd->uf_port_next= NULL;
       

Returns the index to the udp_fd_table for the udp channel.

   225          return i;
       
   226  }
       

udp_get_data is called by the ip interface. It is called with count != 0 to get the
data (usually passed by the user eg a write system call) to the inet process. It is
called with count = 0 to return an integer result (eg the integer result in a write sytem call).

   227  PRIVATE acc_t *udp_get_data (port, offset, count, for_ioctl)
   228  int port;
   229  size_t offset;
   230  size_t count;
   231  int for_ioctl;
   232  {
   233          udp_port_t *udp_port;
   234          udp_fd_t *udp_fd;
   235          int result;
       
   236          udp_port= &udp_port_table[port];
       
   237          switch(udp_port->up_state)
   238          {

UPS_SETPROTO = Beginning configuration of ip channel.
Called by the ip interface when the udp interface calls ip_ioctl(udp_port->up_ipfd, NWIOSIPOPT) in udp_main().

   239          case UPS_SETPROTO:
   240  assert (for_ioctl);
   241                  if (!count)

Returns integer result of NWIOSIPOPT ioctl call. If result >= 0 the ioctl call was successful.
If it was successful, then get the ip address by calling udp_main() in state UPS_GETCONF.

   242                  {
   243                          result= (int)offset;
   244                          if (result<0)
   245                          {
   246                                  udp_port->up_state= UPS_ERROR;
   247                                  break;
   248                          }
   249                          udp_port->up_state= UPS_GETCONF;
   250                          if (udp_port->up_flags & UPF_SUSPEND)
   251                                  udp_main(udp_port);
   252                          return NULL;
   253                  }
   254                  else

Returns the nwio_ipopt structure which is passed to the ip interface in a NWIOSIPOPT ioctl call.

   255                  {
   256                          struct nwio_ipopt *ipopt;
   257                          acc_t *acc;
       
   258  assert (!offset);
   259  assert (count == sizeof(*ipopt));
       
   260                          acc= bf_memreq(sizeof(*ipopt));
   261                          ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
   262                          ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC |
   263                                  NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC |
   264                                  NWIO_HDR_O_ANY | NWIO_RWDATALL;
   265                          ipopt->nwio_proto= IPPROTO_UDP;
   266                          return acc;
   267                  }

UPS_MAIN = IP Channel has reported the ip address of the channel to the upd interface. udp channel has been configured.

   268          case UPS_MAIN:
   269  assert (!for_ioctl);
   270  assert (udp_port->up_flags & UPF_WRITE_IP);
   271                  if (!count)

If called with count = 0 it returns an integer result (eg the integer result in a write system call).

   272                  {
   273                          result= (int)offset;
   274  assert (udp_port->up_wr_pack);
   275                          bf_afree(udp_port->up_wr_pack);
   276                          udp_port->up_wr_pack= 0;

udp_get_data checks if the port is susupended on a write call.
UPF_WRITE_SP means suspended on a write system call.
udp_get_data checks if the port is susupended on a write call.

   277                          if (udp_port->up_flags & UPF_WRITE_SP)
   278                          {

If so it attempts to rewrite the message stored in up_write_fd. up_write_fd stores the first fd which has a suspended write call.

   279                                  if (udp_port->up_write_fd)
   280                                  {
   281                                          udp_fd= udp_port->up_write_fd;
   282                                          udp_port->up_write_fd= NULL;
   283                                          udp_fd->uf_flags &= ~UFF_WRITE_IP;
   284                                          reply_thr_get(udp_fd, result, FALSE);
   285                                  }
   286                                  udp_port->up_flags &= ~(UPF_WRITE_SP |
   287                                          UPF_WRITE_IP);

If there is still a suspended write call it attempts to restart them by calling udp_restart_write_port.

   288                                  if (udp_port->up_flags & UPF_MORE2WRITE)
   289                                  {
   290                                          udp_restart_write_port(udp_port);
   291                                  }
   292                          }
   293                          else

Mark udp_port as no longer writing.

   294                                  udp_port->up_flags &= ~UPF_WRITE_IP;
   295                  }
   296                  else

If called with count != 0 it returns data (usually passed by the user process).

   297                  {
   298                          return bf_cut (udp_port->up_wr_pack, offset, count);
   299                  }
   300                  break;
   301          default:
   302  #if !CRAMPED
   303                  printf("udp_get_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n",
   304                          port, offset, count, udp_port->up_state);
   305  #endif
   306                  break;
   307          }
   308          return NULL;
   309  }
       

udp_put_data is called by the ip protocol interface. udp_put_data returns data specific to the
udp port table (eg ip errors and ip ioctl calls). It is called with count != 0 to send the data (usually passed by
the user eg a read system call) to udp and often to the user process. It is called with count = 0 to return an
integer result (eg the integer result in a read sytem call).

   310  PRIVATE int udp_put_data (fd, offset, data, for_ioctl)
   311  int fd;
   312  size_t offset;
   313  acc_t *data;
   314  int for_ioctl;
   315  {
   316          udp_port_t *udp_port;
   317          int result;
       
   318          udp_port= &udp_port_table[fd];
       
   319          switch (udp_port->up_state)
   320          {

UPS_GETCONF = IP Channel has been configured using the NWIOSIPOPT ioctl call for the ip device.
Next step is to get the ip address of the ip channel.

   321          case UPS_GETCONF:
   322                  if (!data)

Returns integer result of NWIOGIPCONF ioctl call. If result >= 0 the ioctl call was successful.
If it was successful, then start reading packets by calling udp_main() in state UPF_SUSPEND.

   323                  {
   324                          result= (int)offset;
   325                          if (result<0)
   326                          {
   327                                  udp_port->up_state= UPS_ERROR;
   328                                  return NW_OK;
   329                          }
   330                          udp_port->up_state= UPS_MAIN;
   331                          if (udp_port->up_flags & UPF_SUSPEND)
   332                                  udp_main(udp_port);
   333                  }
   334                  else

Set IP Address. Returned from the NWIOGIPCONF IOCTL system call.

   335                  {
   336                          struct nwio_ipconf *ipconf;
       
   337                          data= bf_packIffLess(data, sizeof(*ipconf));
   338                          ipconf= (struct nwio_ipconf *)ptr2acc_data(data);
   339  assert (ipconf->nwic_flags & NWIC_IPADDR_SET);
   340                          udp_port->up_ipaddr= ipconf->nwic_ipaddr;
   341                          bf_afree(data);
   342                  }
   343                  break;

UPS_MAIN = IP Channel has reported the ip address of the channel to the upd interface. udp channel has been configured.
udp_put_data is called in mode UPS_MAIN after udp is configured so that ip should be performing a read/ ioctl.

   344          case UPS_MAIN:
   345                  assert(0);
       
   346                  assert (udp_port->up_flags & UPF_READ_IP);
   347                  if (!data)

If called with data = NULL it returns either an integer result to a ioctl call or reports an error.
Since no ioctl calls should be made to the ip device when up_state = UPS_MAIN, the result (ie offset)
should be less than 0 to report an error.

   348                  {
   349                          result= (int)offset;
   350                          compare (result, >=, 0);

After the integer result is passed, udp_put_data checks if the port is suspended on a read call.
If so it attempts to restart reading the messages by calling read_ip_packets.

   351                          if (udp_port->up_flags & UPF_READ_SP)
   352                          {
   353                                  udp_port->up_flags &= ~(UPF_READ_SP|
   354                                          UPF_READ_IP);
   355                                  read_ip_packets(udp_port);
   356                          }
   357                          else
   358                                  udp_port->up_flags &= ~UPF_READ_IP;
   359                  }
   360                  else
   361                  {

Not a valid assertion because it is returning a data from a read system call which is not
data specific to a udp port table entry but specific to a udp fd table entry ie a udp channel.
IP interface should be using udp_ip_arrived to return the data.

   362  assert (!offset);       /* This isn't a valid assertion but ip sends only
   363                           * whole datagrams up */
   364                          udp_ip_arrived(fd, data, bf_bufsize(data));
   365                  }
   366                  break;
   367          default:
   368                  ip_panic((
   369                  "udp_put_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n",
   370                                          fd, offset, data, udp_port->up_state ));
   371          }
   372          return NW_OK;
   373  }
       

Implements the ioctl system call on the UDP device.

   374  int udp_ioctl (fd, req)
   375  int fd;
   376  ioreq_t req;
   377  {
   378          udp_fd_t *udp_fd;
   379          udp_port_t *udp_port;
   380          nwio_udpopt_t *udp_opt;
   381          acc_t *opt_acc;
   382          int result;
       
   383          udp_fd= &udp_fd_table[fd];
       
   384  assert (udp_fd->uf_flags & UFF_INUSE);
       
   385          udp_port= udp_fd->uf_port;

Marks the udp channel as processing a IOCTL call.

   386          udp_fd->uf_flags |= UFF_IOCTL_IP;

Saves the IOCTL request in case IOCTL call gets suspended.

   387          udp_fd->uf_ioreq= req;
       

Suspend call if ip channel has not been fully configured and returned ip address.

   388          if (udp_port->up_state != UPS_MAIN)
   389                  return NW_SUSPEND;
       
   390          switch(req)
   391          {

Implements the ioctl system call on the UDP device with parameter NWIOSUDPOPT.
Description of the ioctl system call is given in the ip(4) manual here.
Therefore descriptions will be brief.

   392          case NWIOSUDPOPT:
   393                  result= udp_setopt(udp_fd);
   394                  break;

Implements the ioctl system call on the UDP device with parameter NWIOGUDPOPT.
Description of the ioctl system call is given in the ip(4) manual here.
Therefore descriptions will be brief.

   395          case NWIOGUDPOPT:
   396                  opt_acc= bf_memreq(sizeof(*udp_opt));
   397  assert (opt_acc->acc_length == sizeof(*udp_opt));
   398                  udp_opt= (nwio_udpopt_t *)ptr2acc_data(opt_acc);
       
   399                  *udp_opt= udp_fd->uf_udpopt;

Set local IP Address to nwuo_locaddr.

   400                  udp_opt->nwuo_locaddr= udp_fd->uf_port->up_ipaddr;
   401                  result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, 0, opt_acc,
   402                          TRUE);
   403                  if (result == NW_OK)
   404                          reply_thr_put(udp_fd, NW_OK, TRUE);
   405                  break;
   406          default:
   407                  reply_thr_get(udp_fd, EBADIOCTL, TRUE);
   408                  result= NW_OK;
   409                  break;
   410          }

If IOCTL call was processed marked the udp channel as no longer processing the IOCTL call.

   411          if (result != NW_SUSPEND)
   412                  udp_fd->uf_flags &= ~UFF_IOCTL_IP;
   413          return result;
   414  }
       

Implements the ioctl system call on the UDP device with parameter NWIOGUDPOPT.
Description of the ioctl system call is given in the ip(4) manual here.

   415  PRIVATE int udp_setopt(udp_fd)
   416  udp_fd_t *udp_fd;
   417  {
   418          udp_fd_t *fd_ptr;
   419          nwio_udpopt_t oldopt, newopt;
   420          acc_t *data;
   421          int result;
   422          udpport_t port;
   423          unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags,
   424                  all_flags, flags;
   425          unsigned long new_flags;
   426          int i;
       
   427          data= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0,
   428                  sizeof(nwio_udpopt_t), TRUE);
       
   429          if (!data)
   430                  return EFAULT;
       
   431          data= bf_packIffLess(data, sizeof(nwio_udpopt_t));
   432  assert (data->acc_length == sizeof(nwio_udpopt_t));
       
   433          newopt= *(nwio_udpopt_t *)ptr2acc_data(data);
   434          bf_afree(data);
   435          oldopt= udp_fd->uf_udpopt;
       
   436          old_en_flags= oldopt.nwuo_flags & 0xffff;
   437          old_di_flags= (oldopt.nwuo_flags >> 16) & 0xffff;
       
   438          new_en_flags= newopt.nwuo_flags & 0xffff;
   439          new_di_flags= (newopt.nwuo_flags >> 16) & 0xffff;
       
   440          if (new_en_flags & new_di_flags)
   441          {
   442                  DBLOCK(1, printf("returning EBADMODE\n"));
       
   443                  reply_thr_get(udp_fd, EBADMODE, TRUE);
   444                  return NW_OK;
   445          }
       
   446          /* NWUO_ACC_MASK */
   447          if (new_di_flags & NWUO_ACC_MASK)
   448          {
   449                  DBLOCK(1, printf("returning EBADMODE\n"));
       
   450                  reply_thr_get(udp_fd, EBADMODE, TRUE);
   451                  return NW_OK;
   452                  /* access modes can't be disabled */
   453          }
       
   454          if (!(new_en_flags & NWUO_ACC_MASK))
   455                  new_en_flags |= (old_en_flags & NWUO_ACC_MASK);
       
   456          /* NWUO_LOCPORT_MASK */
   457          if (new_di_flags & NWUO_LOCPORT_MASK)
   458          {
   459                  DBLOCK(1, printf("returning EBADMODE\n"));
       
   460                  reply_thr_get(udp_fd, EBADMODE, TRUE);
   461                  return NW_OK;
   462                  /* the loc ports can't be disabled */
   463          }
   464          if (!(new_en_flags & NWUO_LOCPORT_MASK))
   465          {
   466                  new_en_flags |= (old_en_flags & NWUO_LOCPORT_MASK);
   467                  newopt.nwuo_locport= oldopt.nwuo_locport;
   468          }
   469          else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL)
   470          {
   471                  newopt.nwuo_locport= find_unused_port(udp_fd-udp_fd_table);
   472          }
   473          else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
   474          {
   475                  if (!newopt.nwuo_locport)
   476                  {
   477                          DBLOCK(1, printf("returning EBADMODE\n"));
       
   478                          reply_thr_get(udp_fd, EBADMODE, TRUE);
   479                          return NW_OK;
   480                  }
   481          }
       
   482          /* NWUO_LOCADDR_MASK */
   483          if (!((new_en_flags | new_di_flags) & NWUO_LOCADDR_MASK))
   484          {
   485                  new_en_flags |= (old_en_flags & NWUO_LOCADDR_MASK);
   486                  new_di_flags |= (old_di_flags & NWUO_LOCADDR_MASK);
   487          }
       
   488          /* NWUO_BROAD_MASK */
   489          if (!((new_en_flags | new_di_flags) & NWUO_BROAD_MASK))
   490          {
   491                  new_en_flags |= (old_en_flags & NWUO_BROAD_MASK);
   492                  new_di_flags |= (old_di_flags & NWUO_BROAD_MASK);
   493          }
       
   494          /* NWUO_REMPORT_MASK */
   495          if (!((new_en_flags | new_di_flags) & NWUO_REMPORT_MASK))
   496          {
   497                  new_en_flags |= (old_en_flags & NWUO_REMPORT_MASK);
   498                  new_di_flags |= (old_di_flags & NWUO_REMPORT_MASK);
   499                  newopt.nwuo_remport= oldopt.nwuo_remport;
   500          }
   501         
   502          /* NWUO_REMADDR_MASK */
   503          if (!((new_en_flags | new_di_flags) & NWUO_REMADDR_MASK))
   504          {
   505                  new_en_flags |= (old_en_flags & NWUO_REMADDR_MASK);
   506                  new_di_flags |= (old_di_flags & NWUO_REMADDR_MASK);
   507                  newopt.nwuo_remaddr= oldopt.nwuo_remaddr;
   508          }
       
   509          /* NWUO_RW_MASK */
   510          if (!((new_en_flags | new_di_flags) & NWUO_RW_MASK))
   511          {
   512                  new_en_flags |= (old_en_flags & NWUO_RW_MASK);
   513                  new_di_flags |= (old_di_flags & NWUO_RW_MASK);
   514          }
       
   515          /* NWUO_IPOPT_MASK */
   516          if (!((new_en_flags | new_di_flags) & NWUO_IPOPT_MASK))
   517          {
   518                  new_en_flags |= (old_en_flags & NWUO_IPOPT_MASK);
   519                  new_di_flags |= (old_di_flags & NWUO_IPOPT_MASK);
   520          }
       
   521          new_flags= ((unsigned long)new_di_flags << 16) | new_en_flags;
   522          if ((new_flags & NWUO_RWDATONLY) &&
   523                  ((new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_ANY ||
   524                  (new_flags & (NWUO_RP_ANY|NWUO_RA_ANY|NWUO_EN_IPOPT))))
   525          {
   526                  DBLOCK(1, printf("returning EBADMODE\n"));
       
   527                  reply_thr_get(udp_fd, EBADMODE, TRUE);
   528                  return NW_OK;
   529          }
       
   530          /* Check the access modes */
   531          if ((new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL ||
   532                  (new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
   533          {
   534                  for (i= 0, fd_ptr= udp_fd_table; i<UDP_FD_NR; i++, fd_ptr++)
   535                  {
   536                          if (fd_ptr == udp_fd)
   537                                  continue;
   538                          if (!(fd_ptr->uf_flags & UFF_INUSE))
   539                                  continue;
   540                          if (fd_ptr->uf_port != udp_fd->uf_port)
   541                                  continue;
   542                          flags= fd_ptr->uf_udpopt.nwuo_flags;
   543                          if ((flags & NWUO_LOCPORT_MASK) != NWUO_LP_SEL &&
   544                                  (flags & NWUO_LOCPORT_MASK) != NWUO_LP_SET)
   545                                  continue;
   546                          if (fd_ptr->uf_udpopt.nwuo_locport !=
   547                                  newopt.nwuo_locport)
   548                          {
   549                                  continue;
   550                          }
   551                          if ((flags & NWUO_ACC_MASK) !=
   552                                  (new_flags & NWUO_ACC_MASK))
   553                          {
   554                                  DBLOCK(1, printf(
   555                          "address inuse: new fd= %d, old_fd= %d, port= %u\n",
   556                                          udp_fd-udp_fd_table,
   557                                          fd_ptr-udp_fd_table,
   558                                          newopt.nwuo_locport));
       
   559                                  reply_thr_get(udp_fd, EADDRINUSE, TRUE);
   560                                  return NW_OK;
   561                          }
   562                  }
   563          }
       
   564          if (udp_fd->uf_flags & UFF_OPTSET)
   565                  unhash_fd(udp_fd);
       
   566          newopt.nwuo_flags= new_flags;
   567          udp_fd->uf_udpopt= newopt;
       
   568          all_flags= new_en_flags | new_di_flags;
   569          if ((all_flags & NWUO_ACC_MASK) && (all_flags & NWUO_LOCPORT_MASK) &&
   570                  (all_flags & NWUO_LOCADDR_MASK) &&
   571                  (all_flags & NWUO_BROAD_MASK) &&
   572                  (all_flags & NWUO_REMPORT_MASK) &&
   573                  (all_flags & NWUO_REMADDR_MASK) &&
   574                  (all_flags & NWUO_RW_MASK) &&
   575                  (all_flags & NWUO_IPOPT_MASK))
   576                  udp_fd->uf_flags |= UFF_OPTSET;
   577          else
   578          {
   579                  udp_fd->uf_flags &= ~UFF_OPTSET;
   580          }
       
   581          if (udp_fd->uf_flags & UFF_OPTSET)
   582                  hash_fd(udp_fd);
       
   583          reply_thr_get(udp_fd, NW_OK, TRUE);
   584          return NW_OK;
   585  }
       

find_unused_port() returns an unused local port.

   586  PRIVATE udpport_t find_unused_port(fd)
   587  int fd;
   588  {
   589          udpport_t port, nw_port;
       
   590          for (port= 0x8000; port < 0xffff-UDP_FD_NR; port+= UDP_FD_NR)
   591          {
   592                  nw_port= htons(port);
   593                  if (is_unused_port(nw_port))
   594                          return nw_port;
   595          }
   596          for (port= 0x8000; port < 0xffff; port++)
   597          {
   598                  nw_port= htons(port);
   599                  if (is_unused_port(nw_port))
   600                          return nw_port;
   601          }
   602          ip_panic(( "unable to find unused port (shouldn't occur)" ));
   603          return 0;
   604  }
       
   605  /*
   606  reply_thr_put
   607  */
       

reply_thr_put() returns an integer result to the user process processing a write or ioctl
system call.

   608  PRIVATE void reply_thr_put(udp_fd, reply, for_ioctl)
   609  udp_fd_t *udp_fd;
   610  int reply;
   611  int for_ioctl;
   612  {
   613          int result;
       
   614          result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, reply,
   615                  (acc_t *)0, for_ioctl);
   616          assert(result == NW_OK);
   617  }
       

reply_thr_get() returns an integer result to the user process processing a read or ioctl
system call.

   618  /*
   619  reply_thr_get
   620  */
       
   621  PRIVATE void reply_thr_get(udp_fd, reply, for_ioctl)
   622  udp_fd_t *udp_fd;
   623  int reply;
   624  int for_ioctl;
   625  {
   626          acc_t *result;
   627          result= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, reply,
   628                  (size_t)0, for_ioctl);
   629          assert (!result);
   630  }
       

is_unused_port() returns true if port is an unused port. It returns false if port is a
used port.

   631  PRIVATE int is_unused_port(port)
   632  udpport_t port;
   633  {
   634          int i;
   635          udp_fd_t *udp_fd;
       
   636          for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++,
   637                  udp_fd++)
   638          {
   639                  if (!(udp_fd->uf_flags & UFF_OPTSET))
   640                          continue;
   641                  if (udp_fd->uf_udpopt.nwuo_locport == port)
   642                          return FALSE;
   643          }
   644          return TRUE;
   645  }
       

read_ip_packets reads all packets which are in the ip queue waiting to be read. read_ip_packets needs to be called
in order to ensure that packets in the queue are read at the beginning immediately after the udp interface has been
configured. If packets are in the queue, the IP interface returns those packets by calling udp_ip_arrived().

   646  PRIVATE void read_ip_packets(udp_port)
   647  udp_port_t *udp_port;
   648  {
   649          int result;
       
   650          do
   651          {

Mark that the udp interface is processing a read call on the port.

   652                  udp_port->up_flags |= UPF_READ_IP;

Check for packet to read.

   653                  result= ip_read(udp_port->up_ipfd, UDP_MAX_DATAGRAM);

If there is no such packet to read result == NW_SUSPEND.

   654                  if (result == NW_SUSPEND)
   655                  {
   656                          udp_port->up_flags |= UPF_READ_SP;
   657                          return;
   658                  }
   659  assert(result == NW_OK);

Unmark that the udp interface is processing a read call on the port.

   660                  udp_port->up_flags &= ~UPF_READ_IP;
   661          } while(!(udp_port->up_flags & UPF_READ_IP));
   662  }
       
       

udp_read() implements read system call.

   663  PUBLIC int udp_read (fd, count)
   664  int fd;
   665  size_t count;
   666  {
   667          udp_fd_t *udp_fd;
   668          acc_t *tmp_acc, *next_acc;
       
   669          udp_fd= &udp_fd_table[fd];

Check if udp channel has been configured.

   670          if (!(udp_fd->uf_flags & UFF_OPTSET))
   671          {
   672                  reply_thr_put(udp_fd, EBADMODE, FALSE);
   673                  return NW_OK;
   674          }
       

Save size of data which is to be read in case read call gets suspended.

   675          udp_fd->uf_rd_count= count;
       

Check if any data has arrived yet.

   676          if (udp_fd->uf_rdbuf_head)
   677          {

If packet has not expired yet, return packet to user.

   678                  if (get_time() <= udp_fd->uf_exp_tim)
   679                          return udp_packet2user (udp_fd);

If packet has expired, free all remaining packets and suspend the udp channel.

   680                  tmp_acc= udp_fd->uf_rdbuf_head;
   681                  while (tmp_acc)
   682                  {
   683                          next_acc= tmp_acc->acc_ext_link;
   684                          bf_afree(tmp_acc);
   685                          tmp_acc= next_acc;
   686                  }
   687                  udp_fd->uf_rdbuf_head= NULL;
   688          }
   689          udp_fd->uf_flags |= UFF_READ_IP;
   690          return NW_SUSPEND;
   691  }
       

udp_packet2user() sends packet to user.

   692  PRIVATE int udp_packet2user (udp_fd)
   693  udp_fd_t *udp_fd;
   694  {
   695          acc_t *pack, *tmp_pack;
   696          udp_io_hdr_t *hdr;
   697          int result, hdr_len;
   698          size_t size, transf_size;
       
   699          pack= udp_fd->uf_rdbuf_head;
   700          udp_fd->uf_rdbuf_head= pack->acc_ext_link;
       
   701          size= bf_bufsize (pack);
       

NWUO_RWDATONLY = only the data part of a UDP packet is sent to the server and only the data part is received from the server.

   702          if (udp_fd->uf_udpopt.nwuo_flags & NWUO_RWDATONLY)
   703          {

If NWUO_RWDATONLY is set then the udp_io_hdr_t header and any ip options following the header is not returned at the start of the udp packet.

       
   704                  pack= bf_packIffLess (pack, UDP_IO_HDR_SIZE);
   705                  assert (pack->acc_length >= UDP_IO_HDR_SIZE);
       
   706                  hdr= (udp_io_hdr_t *)ptr2acc_data(pack);
   707  #if CONF_UDP_IO_NW_BYTE_ORDER
   708                  hdr_len= UDP_IO_HDR_SIZE+NTOHS(hdr->uih_ip_opt_len);
   709  #else
   710                  hdr_len= UDP_IO_HDR_SIZE+hdr->uih_ip_opt_len;
   711  #endif
       
   712                  assert (size>= hdr_len);
   713                  size -= hdr_len;
   714                  tmp_pack= bf_cut(pack, hdr_len, size);
   715                  bf_afree(pack);
   716                  pack= tmp_pack;
   717          }
       

The new packet is returned adjusting for the size as stored in uf_rd_count which was set by the read system call.

   718          if (size>udp_fd->uf_rd_count)
   719          {
   720                  tmp_pack= bf_cut (pack, 0, udp_fd->uf_rd_count);
   721                  bf_afree(pack);
   722                  pack= tmp_pack;
   723                  transf_size= udp_fd->uf_rd_count;
   724          }
   725          else
   726                  transf_size= size;
       

The packet is then sent back to the user by calling uf_put_userdata.

   727          result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
   728                  (size_t)0, pack, FALSE);
       
   729          if (result >= 0)

If size requested in the read system call is less than the size of the packet the integer result returned is EPACKSIZE.

   730                  if (size > transf_size)
   731                          result= EPACKSIZE;
   732                  else

If the size requested in the read system call is greater than or equal to the size of the packet, the size of the returned packet is returned as the integer result.

   733                          result= transf_size;
       
   734          udp_fd->uf_flags &= ~UFF_READ_IP;

An integer result is passed backed to the user by calling uf_put_userdata again.

   735          result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, result,
   736                          (acc_t *)0, FALSE);
   737  assert (result == 0);
       
   738          return result;
   739  }
       

udp_ip_arrived() is called by the IP interface when a packet has arrrived.

   740  PRIVATE void udp_ip_arrived(port, pack, pack_size)
   741  int port;
   742  acc_t *pack;
   743  size_t pack_size;
   744  {
   745          udp_port_t *udp_port;
   746          udp_fd_t *udp_fd, *share_fd;
   747          acc_t *ip_hdr_acc, *udp_acc, *ipopt_pack, *no_ipopt_pack, *tmp_acc;
   748          ip_hdr_t *ip_hdr;
   749          udp_hdr_t *udp_hdr;
   750          udp_io_hdr_t *udp_io_hdr;
   751          size_t ip_hdr_size, udp_size, data_size, opt_size;
   752          ipaddr_t src_addr, dst_addr;
   753          udpport_t src_port, dst_port;
   754          u8_t u16[2];
   755          u16_t chksum;
   756          unsigned long dst_type, flags;
   757          time_t  exp_tim;
   758          int i, delivered, hash;
       
   759          udp_port= &udp_port_table[port];
       
   760          ip_hdr_acc= bf_cut(pack, 0, IP_MIN_HDR_SIZE);
   761          ip_hdr_acc= bf_packIffLess(ip_hdr_acc, IP_MIN_HDR_SIZE);

ip_hdr = ip header.

   762          ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_acc);
   763          ip_hdr_size= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
   764          if (ip_hdr_size != IP_MIN_HDR_SIZE)
   765          {
   766                  bf_afree(ip_hdr_acc);
   767                  ip_hdr_acc= bf_cut(pack, 0, ip_hdr_size);
   768                  ip_hdr_acc= bf_packIffLess(ip_hdr_acc, ip_hdr_size);
   769                  ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_acc);
   770          }
       

The ip header is automatically deleted from the return packet by calling bf_delhead().

   771          udp_acc= bf_delhead(pack, ip_hdr_size);
   772          pack= NULL;
       
   773          pack_size -= ip_hdr_size;
   774          if (pack_size < UDP_HDR_SIZE)
   775          {
   776                  DBLOCK(1, printf("packet too small\n"));
       
   777                  bf_afree(ip_hdr_acc);
   778                  bf_afree(udp_acc);
   779                  return;
   780          }
       
   781          udp_acc= bf_packIffLess(udp_acc, UDP_HDR_SIZE);

udp_hdr = udp header.

   782          udp_hdr= (udp_hdr_t *)ptr2acc_data(udp_acc);
   783          udp_size= ntohs(udp_hdr->uh_length);
   784          if (udp_size > pack_size)
   785          {
   786                  DBLOCK(1, printf("packet too large\n"));
       
   787                  bf_afree(ip_hdr_acc);
   788                  bf_afree(udp_acc);
   789                  return;
   790          }
       

src_addr = source ip address.

   791          src_addr= ip_hdr->ih_src;

dst_addr = destination ip address.

   792          dst_addr= ip_hdr->ih_dst;
       

Next there is a checksum check.

   793          if (udp_hdr->uh_chksum)
   794          {
   795                  u16[0]= 0;
   796                  u16[1]= ip_hdr->ih_proto;
   797                  chksum= pack_oneCsum(udp_acc);
   798                  chksum= oneC_sum(chksum, (u16_t *)&src_addr, sizeof(ipaddr_t));
   799                  chksum= oneC_sum(chksum, (u16_t *)&dst_addr, sizeof(ipaddr_t));
   800                  chksum= oneC_sum(chksum, (u16_t *)u16, sizeof(u16));
   801                  chksum= oneC_sum(chksum, (u16_t *)&udp_hdr->uh_length,
   802                          sizeof(udp_hdr->uh_length));
   803                  if (~chksum & 0xffff)
   804                  {
   805                          DBLOCK(1, printf("checksum error in udp packet\n");
   806                                  printf("src ip_addr= ");
   807                                  writeIpAddr(src_addr);
   808                                  printf(" dst ip_addr= ");
   809                                  writeIpAddr(dst_addr);
   810                                  printf("\n");
   811                                  printf("packet chksum= 0x%x, sum= 0x%x\n",
   812                                          udp_hdr->uh_chksum, chksum));
       
   813                          bf_afree(ip_hdr_acc);
   814                          bf_afree(udp_acc);
   815                          return;
   816                  }
   817          }
       

exp_tim = expiration time.

   818          exp_tim= get_time() + UDP_READ_EXP_TIME;

src_port = source port.

   819          src_port= udp_hdr->uh_src_port;

dst_port = destination port.

   820          dst_port= udp_hdr->uh_dst_port;
       
   821          /* Send an ICMP port unreachable if the packet could not be
   822           * delivered.
   823           */
   824          delivered= 0;
       

From Minix Manual
The locaddr flags control the reception of packets. NWUO_EN_LOC enables
the reception of packets with the local IP address as destination.
NWUO_DI_LOC disables the reception of packet for the local IP address.
The broad flags control the reception of broadcast packets.
NWUO_EN_BROAD enables the reception of broadcast packets and
NWUO_DI_BROAD disables the reception of broadcast packets.


   825          if (dst_addr == udp_port->up_ipaddr)
   826                  dst_type= NWUO_EN_LOC;
   827          else
   828          {
   829                  dst_type= NWUO_EN_BROAD;
       
   830                  /* Don't send ICMP error packets for broadcast packets */
   831                  delivered= 1;
   832          }
       
   833          DBLOCK(0x20, printf("udp: got packet from ");
   834                  writeIpAddr(src_addr);
   835                  printf(".%u to ", ntohs(src_port));
   836                  writeIpAddr(dst_addr);
   837                  printf(".%u\n", ntohs(dst_port)));
       
   838          no_ipopt_pack= bf_memreq(UDP_IO_HDR_SIZE);
   839          udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(no_ipopt_pack);
   840          udp_io_hdr->uih_src_addr= src_addr;
   841          udp_io_hdr->uih_dst_addr= dst_addr;
   842          udp_io_hdr->uih_src_port= src_port;
   843          udp_io_hdr->uih_dst_port= dst_port;
   844          data_size = udp_size-UDP_HDR_SIZE;

Next it checks over the ip options from the ip header. If there are ip options the ip options
are placed in the packet after the udp_io_hdr and the length of the ip options is stored in the
uih_ip_opt_len field of the udp_io_hdr header.

   845  #if CONF_UDP_IO_NW_BYTE_ORDER
   846          udp_io_hdr->uih_ip_opt_len= HTONS(0);
   847          udp_io_hdr->uih_data_len= htons(data_size);
   848  #else
   849          udp_io_hdr->uih_ip_opt_len= 0;
   850          udp_io_hdr->uih_data_len= data_size;
   851  #endif
   852          no_ipopt_pack->acc_next= bf_cut(udp_acc, UDP_HDR_SIZE, data_size);
       
   853          if (ip_hdr_size == IP_MIN_HDR_SIZE)
   854          {
   855                  ipopt_pack= no_ipopt_pack;
   856                  ipopt_pack->acc_linkC++;
   857          }
   858          else
   859          {
   860                  ipopt_pack= bf_memreq(UDP_IO_HDR_SIZE);
   861                  *(udp_io_hdr_t *)ptr2acc_data(ipopt_pack)= *udp_io_hdr;
   862                  udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(ipopt_pack);
   863                  opt_size = ip_hdr_size-IP_MIN_HDR_SIZE;
   864  #if CONF_UDP_IO_NW_BYTE_ORDER
   865                  udp_io_hdr->uih_ip_opt_len= htons(opt_size);
   866  #else
   867                  udp_io_hdr->uih_ip_opt_len= opt_size;
   868  #endif
   869                  tmp_acc= bf_cut(ip_hdr_acc, (size_t)IP_MIN_HDR_SIZE, opt_size);
   870                  assert(tmp_acc->acc_linkC == 1);
   871                  assert(tmp_acc->acc_next == NULL);
   872                  ipopt_pack->acc_next= tmp_acc;
       
   873                  tmp_acc->acc_next= no_ipopt_pack->acc_next;
   874                  if (tmp_acc->acc_next)
   875                          tmp_acc->acc_next->acc_linkC++;
   876          }
       
   877          hash= dst_port;
   878          hash ^= (hash >> 8);
   879          hash &= (UDP_PORT_HASH_NR-1);
       

udp_ip_arrived next chooses to which fd(s) to send the packet.

   880          for (i= 0; i<2; i++)
   881          {
   882                  share_fd= NULL;
       

It first looks at the linked list whose head is pointed to by the up_port_any field of the port
table entry. up_port_any is the head of a linked list of udp fds which receive messages on any local port. Then it looks at up_port_hash which is a hash table of fds which receive messages
on a specific local port.

   883                  udp_fd= (i == 0) ? udp_port->up_port_any :
   884                          udp_port->up_port_hash[hash];
   885                  for (; udp_fd; udp_fd= udp_fd->uf_port_next)
   886                  {

udp_ip_arrived() chooses which fd(s) it sends the packet to by looking if the udp channel
and packet have the same remote IP address, remote port, and local port.

   887                          if (i && udp_fd->uf_udpopt.nwuo_locport != dst_port)
   888                                  continue;
   889                 
   890                          assert(udp_fd->uf_flags & UFF_INUSE);
   891                          assert(udp_fd->uf_flags & UFF_OPTSET);
   892                 
   893                          if (udp_fd->uf_port != udp_port)
   894                                  continue;
       
   895                          flags= udp_fd->uf_udpopt.nwuo_flags;
   896                          if (!(flags & dst_type))
   897                                  continue;
       
   898                          if ((flags & NWUO_RP_SET) &&
   899                                  udp_fd->uf_udpopt.nwuo_remport != src_port)
   900                          {
   901                                  continue;
   902                          }
       
   903                          if ((flags & NWUO_RA_SET) &&
   904                                  udp_fd->uf_udpopt.nwuo_remaddr != src_addr)
   905                          {
   906                                  continue;
   907                          }
       
   908                          if (i)
   909                          {
   910                                  /* Packet is considdered to be delivered */
   911                                  delivered= 1;
   912                          }
       
   913                          if ((flags & NWUO_ACC_MASK) == NWUO_SHARED &&
   914                                  (!share_fd || !udp_fd->uf_rdbuf_head))
   915                          {
   916                                  share_fd= udp_fd;
   917                                  continue;
   918                          }
       
   919                          if (flags & NWUO_EN_IPOPT)
   920                                  pack= ipopt_pack;
   921                          else
   922                                  pack= no_ipopt_pack;
       
   923                          pack->acc_linkC++;

udp_rd_enqueue is called to put the packet in the queue of the fd.

   924                          udp_rd_enqueue(udp_fd, pack, exp_tim);

If the user process with the file descriptor fd is suspended on a read at the time udp_packet2user
is called to pass the packet to the user.

   925                          if (udp_fd->uf_flags & UFF_READ_IP)
   926                                  udp_packet2user(udp_fd);
   927                  }
       
   928                  if (share_fd)
   929                  {
   930                          flags= share_fd->uf_udpopt.nwuo_flags;
   931                          if (flags & NWUO_EN_IPOPT)
   932                                  pack= ipopt_pack;
   933                          else
   934                                  pack= no_ipopt_pack;
       
   935                          pack->acc_linkC++;

udp_rd_enqueue is called to put the packet in the queue of the fd.

   936                          udp_rd_enqueue(share_fd, pack, exp_tim);

If the user process with the file descriptor fd is suspended on a read at the time udp_packet2user
is called to pass the packet to the user.

   937                          if (share_fd->uf_flags & UFF_READ_IP)
   938                                  udp_packet2user(share_fd);
   939                  }
   940          }
       
   941          if (ipopt_pack)
   942                  bf_afree(ipopt_pack);
   943          if (no_ipopt_pack)
   944                  bf_afree(no_ipopt_pack);
       
   945          if (!delivered)
   946          {
   947                  DBLOCK(0x2, printf("udp: could not deliver packet from ");
   948                          writeIpAddr(src_addr);
   949                          printf(".%u to ", ntohs(src_port));
   950                          writeIpAddr(dst_addr);
   951                          printf(".%u\n", ntohs(dst_port)));
       
   952                  pack= bf_append(ip_hdr_acc, udp_acc);
   953                  ip_hdr_acc= NULL;
   954                  udp_acc= NULL;
   955                  icmp_snd_unreachable(udp_port->up_ipdev, pack,
   956                          ICMP_PORT_UNRCH);
   957                  return;
   958          }
       
   959          assert (ip_hdr_acc);
   960          bf_afree(ip_hdr_acc);
   961          assert (udp_acc);
   962          bf_afree(udp_acc);
   963  }
       

udp_close() implements the close system call on a udp file descriptor fd.

   964  PUBLIC void udp_close(fd)
   965  int fd;
   966  {
   967          udp_fd_t *udp_fd;
   968          acc_t *tmp_acc, *next_acc;
       
   969          udp_fd= &udp_fd_table[fd];
       
   970          assert (udp_fd->uf_flags & UFF_INUSE);
       

Calls unhash_fd() to remove the udp channel from the hash table up_port_hash
or linked list up_port_any of the port table (uf_port) which it belonged to
because the udp channel is no longer being used.

   971          if (udp_fd->uf_flags & UFF_OPTSET)
   972                  unhash_fd(udp_fd);
       
   973          udp_fd->uf_flags= UFF_EMPTY;

Free all of the data it is holding.

   974          tmp_acc= udp_fd->uf_rdbuf_head;
   975          while (tmp_acc)
   976          {
   977                  next_acc= tmp_acc->acc_ext_link;
   978                  bf_afree(tmp_acc);
   979                  tmp_acc= next_acc;
   980          }
   981          udp_fd->uf_rdbuf_head= NULL;
   982  }
       

udp_write implements the write system call on a udp channel.

   983  PUBLIC int udp_write(fd, count)
   984  int fd;
   985  size_t count;
   986  {
   987          udp_fd_t *udp_fd;
   988          udp_port_t *udp_port;
       
   989          udp_fd= &udp_fd_table[fd];
   990          udp_port= udp_fd->uf_port;
       

Checks if udp channel has been configured.

   991          if (!(udp_fd->uf_flags & UFF_OPTSET))
   992          {
   993                  reply_thr_get (udp_fd, EBADMODE, FALSE);
   994                  return NW_OK;
   995          }
       
   996  assert (!(udp_fd->uf_flags & UFF_WRITE_IP));
       

Saves count in case write call gets suspended.

   997          udp_fd->uf_wr_count= count;
       
   998          udp_fd->uf_flags |= UFF_WRITE_IP;
       

Calls restart_write_fd to attempt to write the packet.

   999          restart_write_fd(udp_fd);
       
  1000          if (udp_fd->uf_flags & UFF_WRITE_IP)
  1001          {
  1002                  DBLOCK(1, printf("replying NW_SUSPEND\n"));
       
  1003                  return NW_SUSPEND;
  1004          }
  1005          else
  1006          {
  1007                  return NW_OK;
  1008          }
  1009  }
       

restart_write_fd attempts to write a packet on a udp channel.
It is called from udp_write() and udp_restart_write_port().

  1010  PRIVATE void restart_write_fd(udp_fd)
  1011  udp_fd_t *udp_fd;
  1012  {
  1013          udp_port_t *udp_port;
  1014          acc_t *pack, *ip_hdr_pack, *udp_hdr_pack, *ip_opt_pack, *user_data;
  1015          udp_hdr_t *udp_hdr;
  1016          udp_io_hdr_t *udp_io_hdr;
  1017          ip_hdr_t *ip_hdr;
  1018          size_t ip_opt_size, user_data_size;
  1019          unsigned long flags;
  1020          u16_t chksum;
  1021          u8_t u16[2];
  1022          int result;
       

Gets udp port.

  1023          udp_port= udp_fd->uf_port;
       

If the udp port is currently busy already trying to write a packet, restart_write_fd marks
the port as having more to write (by setting the flag UPF_MORE2WRITE) and returns

  1024          if (udp_port->up_flags & UPF_WRITE_IP)
  1025          {
  1026                  udp_port->up_flags |= UPF_MORE2WRITE;
  1027                  return;
  1028          }
       
  1029  assert (udp_fd->uf_flags & UFF_WRITE_IP);
  1030          udp_fd->uf_flags &= ~UFF_WRITE_IP;
       
  1031  assert (!udp_port->up_wr_pack);
       

It gets the data it needs to write (by calling uf_get_userdata).

  1032          pack= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0,
  1033                  udp_fd->uf_wr_count, FALSE);
  1034          if (!pack)
  1035          {
  1036                  udp_fd->uf_flags &= ~UFF_WRITE_IP;
  1037                  reply_thr_get (udp_fd, EFAULT, FALSE);
  1038                  return;
  1039          }
       
  1040          flags= udp_fd->uf_udpopt.nwuo_flags;
       
  1041          ip_hdr_pack= bf_memreq(IP_MIN_HDR_SIZE);
  1042          ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_pack);
       
  1043          udp_hdr_pack= bf_memreq(UDP_HDR_SIZE);
  1044          udp_hdr= (udp_hdr_t *)ptr2acc_data(udp_hdr_pack);
       

If NWUO_RWDATALL is set, the udp_io_hdr_t header is part of the data packet sent to the inet process.
From Minix manual:
The rw flags control the format of the data to be sent or received. With
NWUO_RWDATONLY only the data part of a UDP packet is sent to the server
and only the data part is received from the server. The NWUO_RWDATALL
mode presents the data part of a UDP packet with a header that contains
the source and destination IP address, source and destination UDP ports,
the IP options, etc. The server expects such a header in front of the
data to be transmitted.

  1045          if (flags & NWUO_RWDATALL)
  1046          {
  1047                  pack= bf_packIffLess(pack, UDP_IO_HDR_SIZE);

pack is prefaced with udp_io_hdr_t header which must be removed before being given
to IP interface.

  1048                  udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(pack);

ip_opt_size = length of ip options.

  1049  #if CONF_UDP_IO_NW_BYTE_ORDER
  1050                  ip_opt_size= ntohs(udp_io_hdr->uih_ip_opt_len);
  1051  #else
  1052                  ip_opt_size= udp_io_hdr->uih_ip_opt_len;
  1053  #endif
  1054                  if (UDP_IO_HDR_SIZE+ip_opt_size>udp_fd->uf_wr_count)
  1055                  {
  1056                          bf_afree(ip_hdr_pack);
  1057                          bf_afree(udp_hdr_pack);
  1058                          bf_afree(pack);
  1059                          reply_thr_get (udp_fd, EINVAL, FALSE);
  1060                          return;
  1061                  }
  1062                  if (ip_opt_size & 3)
  1063                  {
  1064                          bf_afree(ip_hdr_pack);
  1065                          bf_afree(udp_hdr_pack);
  1066                          bf_afree(pack);
  1067                          reply_thr_get (udp_fd, EFAULT, FALSE);
  1068                          return;
  1069                  }

ip_opt_pack = ip options.

  1070                  if (ip_opt_size)
  1071                          ip_opt_pack= bf_cut(pack, UDP_IO_HDR_SIZE, ip_opt_size);
  1072                  else
  1073                          ip_opt_pack= 0;

user_data = payload data.

  1074                  user_data_size= udp_fd->uf_wr_count-UDP_IO_HDR_SIZE-
  1075                          ip_opt_size;
  1076                  user_data= bf_cut(pack, UDP_IO_HDR_SIZE+ip_opt_size,
  1077                          user_data_size);
  1078                  bf_afree(pack);
  1079          }
  1080          else
  1081          {
  1082                  udp_io_hdr= 0;
  1083                  ip_opt_size= 0;
  1084                  user_data_size= udp_fd->uf_wr_count;
  1085                  ip_opt_pack= 0;
  1086                  user_data= pack;
  1087          }
       

ip_hdr is a ip_hdr_t structure. The ip_hdr_t structure is defined in include/net/gen/ip_hdr.h.

typedef struct ip_hdr
{
          u8_t ih_vers_ihl,
                    ih_tos;
          u16_t ih_length,
                    ih_id,
                    ih_flags_fragoff;
          u8_t ih_ttl,
                    ih_proto;
          u16_t ih_hdr_chk;
          ipaddr_t ih_src,
                    ih_dst;
} ip_hdr_t;

The contents of the IP header are defined in RFC 791.

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |Type of Service|          Total Length         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Identification        |Flags|      Fragment Offset    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Time to Live |    Protocol   |         Header Checksum       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Source Address                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Destination Address                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+



The fields of ip_hdr are set to the proper values.

  1088          ip_hdr->ih_vers_ihl= (IP_MIN_HDR_SIZE+ip_opt_size) >> 2;
  1089          ip_hdr->ih_tos= UDP_TOS;
  1090          ip_hdr->ih_flags_fragoff= HTONS(UDP_IP_FLAGS);
  1091          ip_hdr->ih_ttl= UDP_TTL;
  1092          ip_hdr->ih_proto= IPPROTO_UDP;

If the values of the ip header were set in the NWIOSUDPOPT ioctl call we use those
values which were stored in udp_fd->uf_udpopt. From Minix Manual: NWUO_RA_SET sets the
remote IP address the value of nwuo_remaddr. Only packets from that
address will be delivered and all packets will be sent to that address.

  1093          if (flags & NWUO_RA_SET)
  1094          {
  1095                  DBLOCK(1, printf("NWUO_RA_SET\n"));
       
  1096                  ip_hdr->ih_dst= udp_fd->uf_udpopt.nwuo_remaddr;
  1097          }
  1098          else
  1099          {
  1100  assert (udp_io_hdr);
  1101                  ip_hdr->ih_dst= udp_io_hdr->uih_dst_addr;
  1102          }
       

udp_hdr is a udp_hdr_t structure. The udp_hdr_t structure is defined in include/net/gen/udp_hdr.h.

typedef struct udp_hdr {
          udpport_t uh_src_port;
          udpport_t uh_dst_port;
          u16_t uh_length;
          u16_t uh_chksum;
} udp_hdr_t;
The contents of the UDP header are defined in RFC 768.

                  0      7 8     15 16    23 24    31
                 +--------+--------+--------+--------+
                 |     Source      |   Destination   |
                 |      Port       |      Port       |
                 +--------+--------+--------+--------+
                 |                 |                 |
                 |     Length      |    Checksum     |
                 +--------+--------+--------+--------+
                 |
                 |          data octets ...
                 +---------------- ...

                      User Datagram Header Format


From Minix Manual.
The locport flags control the selection of the UDP port for this channel.
NWUO_LP_SEL requests the server to pick a port. This port will be in the
range from 32768 to 65535 and it will be unique. NWUO_LP_SET sets the
local port to the value of the nwuo_locport field. NWUO_LP_ANY does not
select a port. Reception of data is therefore not possible but it is
possible to send data.

  1103          if ((flags & NWUO_LOCPORT_MASK) != NWUO_LP_ANY)
  1104                  udp_hdr->uh_src_port= udp_fd->uf_udpopt.nwuo_locport;
  1105          else
  1106          {
  1107  assert (udp_io_hdr);
  1108                  udp_hdr->uh_src_port= udp_io_hdr->uih_src_port;
  1109          }
       
  1110          if (flags & NWUO_RP_SET)
  1111                  udp_hdr->uh_dst_port= udp_fd->uf_udpopt.nwuo_remport;
  1112          else
  1113          {
  1114  assert (udp_io_hdr);
  1115                  udp_hdr->uh_dst_port= udp_io_hdr->uih_dst_port;
  1116          }
       
  1117          udp_hdr->uh_length= htons(UDP_HDR_SIZE+user_data_size);
  1118          udp_hdr->uh_chksum= 0;
       
  1119          udp_hdr_pack->acc_next= user_data;

Set the checksum field for the udp header.

  1120          chksum= pack_oneCsum(udp_hdr_pack);
  1121          chksum= oneC_sum(chksum, (u16_t *)&udp_fd->uf_port->up_ipaddr,
  1122                  sizeof(ipaddr_t));
  1123          chksum= oneC_sum(chksum, (u16_t *)&ip_hdr->ih_dst, sizeof(ipaddr_t));
  1124          u16[0]= 0;
  1125          u16[1]= IPPROTO_UDP;
  1126          chksum= oneC_sum(chksum, (u16_t *)u16, sizeof(u16));
  1127          chksum= oneC_sum(chksum, (u16_t *)&udp_hdr->uh_length, sizeof(u16_t));
  1128          if (~chksum)
  1129                  chksum= ~chksum;
  1130          udp_hdr->uh_chksum= chksum;
  1131         

If IP options are being used put the ip options into the packet sent to the IP interface.

  1132          if (ip_opt_pack)
  1133          {
  1134                  ip_opt_pack= bf_packIffLess(ip_opt_pack, ip_opt_size);
  1135                  ip_opt_pack->acc_next= udp_hdr_pack;
  1136                  udp_hdr_pack= ip_opt_pack;
  1137          }
  1138          ip_hdr_pack->acc_next= udp_hdr_pack;
       
  1139  assert (!udp_port->up_wr_pack);
  1140  assert (!(udp_port->up_flags & UPF_WRITE_IP));
       

Save packet to write in case write call get suspended.

  1141          udp_port->up_wr_pack= ip_hdr_pack;
  1142          udp_port->up_flags |= UPF_WRITE_IP;
  1143          result= ip_write(udp_port->up_ipfd, bf_bufsize(ip_hdr_pack));
  1144          if (result == NW_SUSPEND)
  1145          {
  1146                  udp_port->up_flags |= UPF_WRITE_SP;
  1147                  udp_fd->uf_flags |= UFF_WRITE_IP;
  1148                  udp_port->up_write_fd= udp_fd;
  1149          }

If write call is not suspended wake up user and return an integer value to it.

  1150          else if (result<0)
  1151                  reply_thr_get(udp_fd, result, FALSE);
  1152          else
  1153                  reply_thr_get (udp_fd, udp_fd->uf_wr_count, FALSE);
  1154  }
       

pack_oneCsum is used to compute the checksum in the udp header.

  1155  PRIVATE u16_t pack_oneCsum(pack)
  1156  acc_t *pack;
  1157  {
  1158          u16_t prev;
  1159          int odd_byte;
  1160          char *data_ptr;
  1161          int length;
  1162          char byte_buf[2];
       
  1163          assert (pack);
       
  1164          prev= 0;
       
  1165          odd_byte= FALSE;
  1166          for (; pack; pack= pack->acc_next)
  1167          {
  1168                 
  1169                  data_ptr= ptr2acc_data(pack);
  1170                  length= pack->acc_length;
       
  1171                  if (!length)
  1172                          continue;
  1173                  if (odd_byte)
  1174                  {
  1175                          byte_buf[1]= *data_ptr;
  1176                          prev= oneC_sum(prev, (u16_t *)byte_buf, 2);
  1177                          data_ptr++;
  1178                          length--;
  1179                          odd_byte= FALSE;
  1180                  }
  1181                  if (length & 1)
  1182                  {
  1183                          odd_byte= TRUE;
  1184                          length--;
  1185                          byte_buf[0]= data_ptr[length];
  1186                  }
  1187                  if (!length)
  1188                          continue;
  1189                  prev= oneC_sum (prev, (u16_t *)data_ptr, length);
  1190          }
  1191          if (odd_byte)
  1192          {
  1193                  byte_buf[1]= 0;
  1194                  prev= oneC_sum (prev, (u16_t *)byte_buf, 1);
  1195          }
  1196          return prev;
  1197  }
       

udp_restart_write_port() is called to restart writing all suspended packets on a specific udp port.

  1198  PRIVATE void udp_restart_write_port(udp_port )
  1199  udp_port_t *udp_port;
  1200  {
  1201          udp_fd_t *udp_fd;
  1202          int i;
       
  1203  assert (!udp_port->up_wr_pack);
  1204  assert (!(udp_port->up_flags & (UPF_WRITE_IP|UPF_WRITE_SP)));
       

UPF_MORE2WRITE is set when udp attempts to write a packet but fails because the port is currently attempting to write another packet.

  1205          while (udp_port->up_flags & UPF_MORE2WRITE)
  1206          {
  1207                  udp_port->up_flags &= ~UPF_MORE2WRITE;
       

Look at each of the udp channels on the udp port to see if there is a packet to write. If so then try to write it
by calling restart_write_fd().

  1208                  for (i= 0, udp_fd= udp_port->up_next_fd; i<UDP_FD_NR;
  1209                          i++, udp_fd++)
  1210                  {
  1211                          if (udp_fd == &udp_fd_table[UDP_FD_NR])
  1212                                  udp_fd= udp_fd_table;
       
  1213                          if (!(udp_fd->uf_flags & UFF_INUSE))
  1214                                  continue;
  1215                          if (!(udp_fd->uf_flags & UFF_WRITE_IP))
  1216                                  continue;
  1217                          if (udp_fd->uf_port != udp_port)
  1218                                  continue;
  1219                          restart_write_fd(udp_fd);

Set UPF_MORE2WRITE and return if the udp port is suspended on the attempt to write a packet.

  1220                          if (udp_port->up_flags & UPF_WRITE_IP)
  1221                          {
  1222                                  udp_port->up_next_fd= udp_fd+1;
  1223                                  udp_port->up_flags |= UPF_MORE2WRITE;
  1224                                  return;
  1225                          }
  1226                  }
  1227          }
  1228  }
       

udp_cancel is called to cancel a read/write/ioctl call.

  1229  PUBLIC int udp_cancel(fd, which_operation)
  1230  int fd;
  1231  int which_operation;
  1232  {
  1233          udp_fd_t *udp_fd;
       
  1234          DBLOCK(0x10, printf("udp_cancel(%d, %d)\n", fd, which_operation));
       
  1235          udp_fd= &udp_fd_table[fd];
       

Unset the flag which says the udp channel is processing the read/write/ioctl call.

  1236          switch (which_operation)
  1237          {
  1238          case SR_CANCEL_READ:
  1239  assert (udp_fd->uf_flags & UFF_READ_IP);
  1240                  udp_fd->uf_flags &= ~UFF_READ_IP;
  1241                  reply_thr_put(udp_fd, EINTR, FALSE);
  1242                  break;
  1243          case SR_CANCEL_WRITE:
  1244  assert (udp_fd->uf_flags & UFF_WRITE_IP);
  1245                  udp_fd->uf_flags &= ~UFF_WRITE_IP;
  1246                  if (udp_fd->uf_port->up_write_fd == udp_fd)
  1247                          udp_fd->uf_port->up_write_fd= NULL;
  1248                  reply_thr_get(udp_fd, EINTR, FALSE);
  1249                  break;
  1250          case SR_CANCEL_IOCTL:
  1251  assert (udp_fd->uf_flags & UFF_IOCTL_IP);
  1252                  udp_fd->uf_flags &= ~UFF_IOCTL_IP;
  1253                  reply_thr_get(udp_fd, EINTR, TRUE);
  1254                  break;
  1255          default:
  1256                  ip_panic(( "got unknown cancel request" ));
  1257          }
  1258          return NW_OK;
  1259  }
       

Called in buf.c to free accessors.

  1260  PRIVATE void udp_buffree (priority)
  1261  int priority;
  1262  {
  1263          int i;
  1264          time_t curr_tim;
  1265          udp_fd_t *udp_fd;
  1266          acc_t *tmp_acc, *next_acc;
       
  1267          if (priority ==  UDP_PRI_FDBUFS_EXTRA)
  1268          {
  1269                  for (i=0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
  1270                  {
  1271                          while (udp_fd->uf_rdbuf_head &&
  1272                                  udp_fd->uf_rdbuf_head->acc_ext_link)
  1273                          {
  1274                                  tmp_acc= udp_fd->uf_rdbuf_head;
  1275                                  udp_fd->uf_rdbuf_head= tmp_acc->acc_ext_link;
  1276                                  bf_afree(tmp_acc);
  1277                          }
  1278                  }
  1279          }
       
  1280          if (priority  == UDP_PRI_FDBUFS)
  1281          {
  1282                  for (i=0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
  1283                  {
  1284                          while (udp_fd->uf_rdbuf_head)
  1285                          {
  1286                                  tmp_acc= udp_fd->uf_rdbuf_head;
  1287                                  udp_fd->uf_rdbuf_head= tmp_acc->acc_ext_link;
  1288                                  bf_afree(tmp_acc);
  1289                          }
  1290                  }
  1291          }
  1292  }
       

udp_rd_enqueue is called by udp_ip_arrived to queue a received message.

  1293  PRIVATE void udp_rd_enqueue(udp_fd, pack, exp_tim)
  1294  udp_fd_t *udp_fd;
  1295  acc_t *pack;
  1296  time_t exp_tim;
  1297  {
  1298          acc_t *tmp_acc;
       

Make a copy of the packet if it is being used by already.

  1299          if (pack->acc_linkC != 1)
  1300          {
  1301                  tmp_acc= bf_dupacc(pack);
  1302                  bf_afree(pack);
  1303                  pack= tmp_acc;
  1304          }

Put at end of queue.

  1305          pack->acc_ext_link= NULL;
  1306          if (udp_fd->uf_rdbuf_head == NULL)
  1307          {
  1308                  udp_fd->uf_exp_tim= exp_tim;
  1309                  udp_fd->uf_rdbuf_head= pack;
  1310          }
  1311          else
  1312                  udp_fd->uf_rdbuf_tail->acc_ext_link= pack;
  1313          udp_fd->uf_rdbuf_tail= pack;
  1314  }
       

hash_fd() puts upd_fd in the hash table up_port_hash (if a local port has been selected) or
in the linked list up_port_any (if a local port has not been selected) of the port table (uf_port).

  1315  PRIVATE void hash_fd(udp_fd)
  1316  udp_fd_t *udp_fd;
  1317  {
  1318          udp_port_t *udp_port;
  1319          int hash;
       
  1320          udp_port= udp_fd->uf_port;
  1321          if ((udp_fd->uf_udpopt.nwuo_flags & NWUO_LOCPORT_MASK) ==
  1322                  NWUO_LP_ANY)

up_port_any points to the head of the linked list which do not have selected local ports.

  1323          {
  1324                  udp_fd->uf_port_next= udp_port->up_port_any;
  1325                  udp_port->up_port_any= udp_fd;
  1326          }
  1327          else
  1328          {

up_port_hash points to the hash table of udp channels which have selected local ports.

  1329                  hash= udp_fd->uf_udpopt.nwuo_locport;
  1330                  hash ^= (hash >> 8);
  1331                  hash &= (UDP_PORT_HASH_NR-1);
       
  1332                  udp_fd->uf_port_next= udp_port->up_port_hash[hash];
  1333                  udp_port->up_port_hash[hash]= udp_fd;
  1334          }
  1335  }
       

unhash_fd removes the upd_fd from the hash table up_port_hash or linked list up_port_any of the port table (uf_port).

  1336  PRIVATE void unhash_fd(udp_fd)
  1337  udp_fd_t *udp_fd;
  1338  {
  1339          udp_port_t *udp_port;
  1340          udp_fd_t *prev, *curr, **udp_fd_p;
  1341          int hash;
       
  1342          udp_port= udp_fd->uf_port;
  1343          if ((udp_fd->uf_udpopt.nwuo_flags & NWUO_LOCPORT_MASK) ==
  1344                  NWUO_LP_ANY)
  1345          {
  1346                  udp_fd_p= &udp_port->up_port_any;
  1347          }
  1348          else
  1349          {
  1350                  hash= udp_fd->uf_udpopt.nwuo_locport;
  1351                  hash ^= (hash >> 8);
  1352                  hash &= (UDP_PORT_HASH_NR-1);
       
  1353                  udp_fd_p= &udp_port->up_port_hash[hash];
  1354          }
  1355          for (prev= NULL, curr= *udp_fd_p; curr;
  1356                  prev= curr, curr= curr->uf_port_next)
  1357          {
  1358                  if (curr == udp_fd)
  1359                          break;
  1360          }
  1361          assert(curr);
  1362          if (prev)
  1363                  prev->uf_port_next= curr->uf_port_next;
  1364          else
  1365                  *udp_fd_p= curr->uf_port_next;
  1366  }
       
  1367  #ifdef BUF_CONSISTENCY_CHECK
  1368  PRIVATE void udp_bufcheck()
  1369  {
  1370          int i;
  1371          udp_port_t *udp_port;
  1372          udp_fd_t *udp_fd;
  1373          acc_t *tmp_acc;
       
  1374          for (i= 0, udp_port= udp_port_table; i<UDP_PORT_NR; i++, udp_port++)
  1375          {
  1376                  if (udp_port->up_wr_pack)
  1377                          bf_check_acc(udp_port->up_wr_pack);
  1378          }
       
  1379          for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
  1380          {
  1381                  for (tmp_acc= udp_fd->uf_rdbuf_head; tmp_acc;
  1382                          tmp_acc= tmp_acc->acc_ext_link)
  1383                  {
  1384                          bf_check_acc(tmp_acc);
  1385                  }
  1386          }
  1387  }
  1388  #endif
       
  1389  /*
  1390   * $PchId: udp.c,v 1.10 1996/08/06 06:48:05 philip Exp $
  1391   */