I recently did a similar project, except that the update was over UART instead of wireless. Everything was in one microcontroller, a Silicon Labs SiM3C166. The on-board flash was logically segmented into 3 sections, the boot loader, the active application and the pending application (there was actually a 4th, small section containing a hash of the pending application, to verify that it had been loaded correctly).
The application code included code to receive the new image and write it into the "pending" section. Once the entire image was loaded and verified against the hash, the code did a soft reset. This starts the bootloader, which is located at address 0.
The function of the bootloader is simple to verify the pending application against its hash and compare it against the existing application. If the hash is valid and the new image is different then the old one, it copies the new application over the old one and then erases the hash.
Finally, regardless of if the application was copied or not, it transferred control to the current application. (This consisted of relocating the interrupt vector block to the application space and branching to the first word of the application.)
Things to note: the application had to be linked to be located at an address other than 0, specifically to the base of the "active" section of flash. This included moving the interrupt vectors. The ARM M3 processor has a system register that points at the interrot vector table and this was used to switch from the boot loader vectors to the application vectors.
Once the application code is running, the boot loader code is not used again until the processor resets.
Hopefully, this will give you an idea of what can be done.