#include <bits/stdc++.h>
using namespace std;
int H, W;
vector<vector<char>> grid;
bool in_grid(int i, int j) { return 0 <= i && i < H && 0 <= j && j < W; }
bool can_step(int i, int j) { return grid[i][j] == '.'; }
int main() {
  cin >> H >> W;
  grid.resize(H, vector<char>(W));
  for (int i = 0; i < H; ++i)
    for (int j = 0; j < W; ++j) cin >> grid[i][j];
  int ans = 0;
  for (int sh = 0; sh < H; ++sh)
    for (int sw = 0; sw < W; ++sw)
      for (int gh = 0; gh < H; ++gh)
        for (int gw = 0; gw < W; ++gw) {
          if (!can_step(sh, sw) || !can_step(gh, gw)) continue;
          vector<vector<int>> visited(H, vector<int>(W));
          using T = tuple<int, int, int>;
          queue<T> q;
          q.push(T(sh, sw, 0));
          visited[sh][sw] = true;
          int dist;
          while (true) {
            T t = q.front();
            q.pop();
            int i, j, d;
            tie(i, j, d) = t;
            visited[i][j] = true;
            if (i == gh && j == gw) {
              dist = d;
              break;
            }
            vector<int> dh{1, 0, -1, 0}, dw{0, 1, 0, -1};
            for (int k = 0; k < 4; ++k) {
              int ni = i + dh[k], nj = j + dw[k];
              if (!in_grid(ni, nj) || !can_step(ni, nj) || visited[ni][nj])
                continue;
              q.push(T(ni, nj, d + 1));
            }
          }
          ans = max(ans, dist);
        }
  cout << ans << endl;
}
