code: func (c *Client) SendAndRead(ctx context.Context, dest *net.UDPAddr, p *dhcp4.Packet, out chan<- *ClientPacket, errCh chan<- *ClientError) {
  	// This ensures that
  	// - we send at most one error on errCh; and
  	// - we don't forget to send err on errCh in the many return statements
  	//   of sendAndRead.
  	if err := c.sendAndRead(ctx, dest, p, out); err != nil {
  		errCh <- err
  	}
  }
docs: // SendAndRead sends the given packet `p` to `dest` and reads responses on the
  // UDP connection. Any valid DHCP reply packet is sent to `out`.
  //
  // SendAndRead blocks reading response packets until either:
  // - `ctx` is canceled; or
  // - we have exhausted all configured retries and timeouts.
  //
  // SendAndRead retries sending the packet and receiving responses according to
  // the configured number of c.retry, using a response timeout of c.timeout.
  //
  // TODO(hugelgupf): Make this a little state machine of packet types. See RFC
  // 2131, Section 4.4, Figure 5.