What mav wrote is pretty correct. However in my experience there are different insert/remove methods that must be used depending on the situation.
When inserting it is best to check first if the list is empty, if so you then do one insert where the head becomes the new node you're trying to create and the head points to null at prev and next. If its not empty you can get creative here. Do you want to insert at the top of the list, as in each node you insert becomes the head or at the bottom of the list, each node you insert becomes the tail.
Removing is where you have to be extra careful, you have to check for null pointers when removing, because if you try to remove something at the end of a list you can get a run time error because you're trying to make a null node point to something, which just makes it unhappy.
Inserting will have 3 different insert methods, is it the first node, is it not the first but becoming the head? or is it becoming the tail? Inserting in the center is an optional fourth way to do it which is a bit easier cause of no nulls to think about but may not be what you need.
So for removing you'll have 3 different methods, is it a node at one of th ends of the list, is it somewhere in the middle, and is it the last node.
Of course some of this can be eliminated if you make a doubly linked ring list but the insert gets a bit more creative and the remove can be cut down a bit.
Looking at your code vs. Mavs code mav did also make the correction that the struct you're using for the list has to refer to itself for the prev/next but are never instantiated until they're used. Hence they're null.
Hope this helps a bit.