I believe you're mixing up a few different threats and attack vectors here.
Threat: MITM sniffing or setting tokens
Location: Public wifi
How to mitigate: Use HTTPS so the connection is secured over TLS/SSL. Also the cookie Secure Flag is recommended, and an HSTS policy with preload.
Threat: XSS
Location: Over the internet
What it is: An attacker injecting JavaScript code into the page, either by enticing their victim to visit a URL for a "reflected XSS" attack, or by storing script within the system's database that is not correctly encoded on output for a "stored XSS" attack. When the attack payload is executed, it comes from the victim's browser and IP.
How to mitigate: Correctly encode output values, implement a Content Security Policy, set X-XSS-Protection
and X-Content-Type-Options
HTTP headers, set the HttpOnly flag on cookies.
Location: Over the internet
What it is: At attacker enticing their victim to visit the attacker's site or a site compromised by the attacker that then makes a malicious request to a good site that the victim is also logged into. When the attack payload is executed, it comes from the victim's browser and IP.
How to mitigate: Generate a random token per session which is passed outside of the cookie mechanism (aka Synchronizer Token Pattern).
Your points
I was wondering what prevents an attacker from generating his/her own
token
Nothing - however if you have associated the token with the user session, Bob's login cannot use Alice's CSRF token and vice versa. Therefore any attacker will not be able to use their own token in a CSRF attack. A good storage location is the server-side session mechanism many web frameworks provide.
Then I began requiring the clients IP to also be stored and checked
during validation. But this would not be secure if our attacker and
victim were on the same network such as a public WiFi hotspot.
A CSRF attack comes from the victim browser. Therefore, the IP address will be the same as the rest of the victim's session. Reading your paragraph again I now realise you may not have been referencing a Man-In-The-Middle situation as I described above, however I've left it in for completeness.
My attempt at a solution: To place a cookie on every user's browser
and to hash their token with the cookie's value so that I can be sure
that it is not an XSS attack.
XSS is a different type of attack. If you have an XSS vulnerability then most CSRF protection mechanisms are either useless or severely compromised.
The mechanism you describe appears to be the Encrypted Token Pattern which is also a valid way to mitigate CSRF.