### BUGGY CODE ###

#!/usr/bin/env python3
from collections import defaultdict
H, W = map(int, input().split())
M = []
for i in range(H):
    M.append(list(input()))


def getLength(Sx, Sy, Gx, Gy):
    def bigcost():
        return 10**16
    costs = defaultdict(bigcost)
    costs[(Sx, Sy)] = 0
    current = [(Sx, Sy)]
    visited = set()
    while len(current) > 0:
        next = []
        for v in current:
            c = costs[v]
            if v[0] > 0 and M[v[1]][v[0]-1] == ".":
                coord = (v[0]-1, v[1])
                if coord not in visited:
                    visited.add(coord)
                    next.append(coord)
                    costs[coord] = min(c+1, costs[coord])
            if v[0] < W-1 and M[v[1]][v[0]+1] == ".":
                coord = (v[0]+1, v[1])
                if coord not in visited:
                    visited.add(coord)
                    next.append(coord)
                    costs[coord] = min(c+1, costs[coord])
            if v[1] < H-1 and M[v[1]+1][v[0]] == ".":
                coord = (v[0], v[1]+1)
                if coord not in visited:
                    visited.add(coord)
                    next.append(coord)
                    costs[coord] = min(c+1, costs[coord])
            if v[1] > 0 and M[v[1]-1][v[0]] == ".":
                coord = (v[0], v[1]-1)
                if coord not in visited:
                    visited.add(coord)
                    next.append(coord)
                    costs[coord] = min(c+1, costs[coord])
        current = next
    return costs[(Gx, Gy)]


result = 0
for Sx in range(W):
    for Gx in range(W):
        for Sy in range(H):
            for Gy in range(H):
                if M[Sy][Sx] == '.' and M[Gy][Gx] == '.':
                    result = max(result, getLength(Sx, Sy, Gx, Gy))
print(result)


### FIXED CODE ###

#!/usr/bin/env python3
from collections import defaultdict
H, W = map(int, input().split())
M = []
for i in range(H):
    M.append(list(input()))


def getMaxDistantPoint(Sx, Sy):
    BIG = 10**16

    def bigcost():
        return BIG
    costs = defaultdict(bigcost)
    costs[(Sx, Sy)] = 0
    current = [(Sx, Sy)]
    visited = set()
    while len(current) > 0:
        next = []
        for v in current:
            c = costs[v]
            if v[0] > 0 and M[v[1]][v[0]-1] == ".":
                coord = (v[0]-1, v[1])
                if coord not in visited:
                    visited.add(coord)
                    next.append(coord)
                    costs[coord] = min(c+1, costs[coord])
            if v[0] < W-1 and M[v[1]][v[0]+1] == ".":
                coord = (v[0]+1, v[1])
                if coord not in visited:
                    visited.add(coord)
                    next.append(coord)
                    costs[coord] = min(c+1, costs[coord])
            if v[1] < H-1 and M[v[1]+1][v[0]] == ".":
                coord = (v[0], v[1]+1)
                if coord not in visited:
                    visited.add(coord)
                    next.append(coord)
                    costs[coord] = min(c+1, costs[coord])
            if v[1] > 0 and M[v[1]-1][v[0]] == ".":
                coord = (v[0], v[1]-1)
                if coord not in visited:
                    visited.add(coord)
                    next.append(coord)
                    costs[coord] = min(c+1, costs[coord])
        current = next
    maxCost = 0
    maxCoord = None
    for c in costs:
        if costs[c] != BIG:
            if costs[c] > maxCost:
                maxCoord = c
                maxCost = costs[c]
    return (maxCoord, maxCost)


result = 0
for Sx in range(W):
    for Sy in range(H):
        if M[Sy][Sx] == '.':
            result = max(result, getMaxDistantPoint(Sx, Sy)[1])
print(result)