using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var input = Console.ReadLine().Split(' ');
        var ySize = int.Parse(input[0]);
        var xSize = int.Parse(input[1]);


        var path = new bool[xSize, ySize];

        for (var i = 0; i < ySize; i++)
        {
            var line = Console.ReadLine().ToCharArray();
            for (var j = 0; j < xSize; j++)
            {
                var isPath = line[j] == '.' ? true : false;
                path[j, i] = isPath;
            }
        }

        var ans = 0;

        for (var i = 0; i < ySize; i++)
        {
            for (int j = 0; j < xSize; j++)
            {
                if(path[j, i])
                {
                    var count = BreadthFirstSearch.CheckExistPath(path, j, i);
                    if(count > ans)
                    {
                        ans = count;
                    }
                }
            }
        }

        Console.WriteLine(ans);
        Console.ReadLine();
    }
}

class BreadthFirstSearch
{
    public static int CheckExistPath(bool[,] maze, int x, int y)
    {
        var queue = new Queue<int[]>();

        queue.Enqueue(new int[2] { x, y });

        var xSize = maze.GetLength(0);
        var ySize = maze.GetLength(1);

        var visited = new bool[xSize, ySize];
        var count = new int[xSize, ySize];

        var finished = false;

        while (!finished)
        {
            if(queue.Count == 0)
            {
                finished = true;
                continue;
            }

            var cell = queue.Dequeue();

            var right = new int[2] { cell[0] + 1, cell[1] };
            if (cell[0] < xSize - 1) 
            {
                if (maze[right[0], right[1]] && !visited[right[0], right[1]])
                {
                    visited[right[0], right[1]] = true;
                    queue.Enqueue(new int[2] { right[0], right[1] });
                    count[right[0], right[1]] = count[cell[0], cell[1]] + 1;
                }
            }

            var down = new int[2] { cell[0], cell[1] + 1 };
            if (cell[1] < ySize - 1)
            {
                if (maze[down[0], down[1]] && !visited[down[0], down[1]])
                {
                    visited[down[0], down[1]] = true;
                    queue.Enqueue(new int[2] { down[0], down[1] });
                    count[down[0], down[1]] = count[cell[0], cell[1]] + 1;
                }
            }

            var left = new int[2] { cell[0] - 1, cell[1] };
            if (cell[0] > 0)
            {
                if (maze[left[0], left[1]] && !visited[left[0], left[1]])
                {
                    visited[left[0], left[1]] = true;
                    queue.Enqueue(new int[2] { left[0], left[1] });
                    count[left[0], left[1]] = count[cell[0], cell[1]] + 1;
                }
            }


            var up = new int[2] { cell[0], cell[1] - 1 };
            if (cell[1] > 0)
            {
                if (maze[up[0], up[1]] && !visited[up[0], up[1]])
                {
                    visited[up[0], up[1]] = true;
                    queue.Enqueue(new int[2] { up[0], up[1] });
                    count[up[0], up[1]] = count[cell[0], cell[1]] + 1;
                }
            }
        }

        var ans = 0;
        foreach (var score in count)
        {
            if (ans < score)
            {
                ans = score;
            }
        }
        return ans;
    }
}