#include <bits/stdc++.h>
using namespace std;
bool isInField(int col, int row, const pair<int, int> &point) {
  const int c = point.second;
  const int r = point.first;
  return (0 <= c && c < col) && (0 <= r && r < row);
}
int main() {
  long long w, h, max = 0;
  cin >> h >> w;
  vector<vector<char>> map(h, vector<char>(w));
  for (long long i = 0; i < h; i++) {
    for (long long j = 0; j < w; j++) cin >> map[i][j];
  }
  const pair<int, int> points[4] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
  for (long long i = 0; i < h; i++) {
    for (long long j = 0; j < w; j++) {
      if (map[i][j] == '.') {
        long long buf = 0;
        vector<vector<int>> memo;
        for (int i = 0; i < h; ++i) {
          vector<int> v(w, 0);
          memo.push_back(v);
        }
        queue<pair<long long, long long>> data;
        data.push({i, j});
        while (!data.empty()) {
          pair<long long, long long> cur = data.front();
          data.pop();
          for (const auto &point : points) {
            pair<long long, long long> next = {(cur.first + point.first),
                                               (cur.second + point.second)};
            if (isInField(w, h, next)) {
              const char s = map[next.first][next.second];
              if (s == '.') {
                if (memo[next.first][next.second] == 0) {
                  data.push(next);
                  memo[next.first][next.second] =
                      memo[cur.first][cur.second] + 1;
                  if (memo[next.first][next.second] > buf)
                    buf = memo[next.first][next.second];
                }
              }
            }
          }
        }
        if (max < buf) max = buf;
      }
    }
  }
  cout << max << endl;
}
