I think that you've outlined the process perfectly. To put the pieces together I would suggest that you create a small plugin (perhaps using the trusty BusinessLogic plugin as a starting point). To communicate with your plugin, add a 'template variable' method to your plugin's variables file, and your geolocation php. For more info see the docs on template variables.
When your template first renders, check for your geo-cookie and assign it to a variable. If the cookie doesn't exist then perform the 'geolocation' using your plugin's template variable method (i.e. 'geoCode'), and set the cookie (i.e. 'myGeoCookie').
{% if getCookie('myGeoCookie') %}
{% set geoCode = getCookie('myGeoCookie') %}
{% else %}
{% set geoCode = craft.businessLogic.geoCode %}
{% 'myGeoCookie'|setCookie(geoCode, now | date_modify("+120 days").timestamp ) %}
{% endif %}
In your plugin's template variable 'geoCode' method you can either perform your geolocation lookup directly and return the resulting 2 letter code, or use it as a wrapper to call a corresponding 'service' method which then passes back the result to the variable, which then returns it to the template.
public function geoCode()
{
// perform lookup
return geoCode;
}
Now with the 'geoCode' variable in your template, you can use it to lookup and display the state specific content from your 'states' section in craft (i.e. called 'stateContent' or whatever you want to call it), which also has a corresponding 'geoCode' field or other identifying attribute (i.e. title). Otherwise display your default content.
{% if geolocationgeocode %}
{% set stateEntry = craft.entries.section('stateContent').geoCode(geoCode).first() %}
{{ stateEntry.body }}
{% else %}
{% otherwise display default content %}
{% endif %}
Not tested. But should be a good starting point.