You say "A struct sllist is has one sentinel field that contains a pointer to
the sentinel node:" - does this mean that there is an empty node separate from
the sllist instance acting as a 'sentinel'? If so, this would seem unnecessary.
And unless struct sllist is going to hold metadata (such as the end of the list, number of
elements), I'm not sure that it is really necessary - you can just use a pointer to the first node.
On return types, I don't see anything wrong with what you have.
For the
_afterfunctions, where does the user get the necessarystruct node*pointer? None of the functions returns astruct node*. Perhaps you have omitted some functions - such assllist_findreturning astruct node*. Such a function would have to take a compare function as a parameter. Also you are missing an 'append' function.On your question 2, the user must have allocated the data in the first place before adding it to the list (as you don't know its size) so it is reasonable to expect her to free it. Conceivably it might not have been dynamically allocated, so you can't safely free it.
Do you intend the structs to be opaque (ie. the user doesn't get to see what is inside them)? In this case you might need a way to iterate through the list. If the structs are not opaque, you are expecting/allowing the user to traverse the list and to manipulate it without using your functions - this is asking for trouble (particularly if you do choose to maintain any metadata) and partially negates the usefulness for the library.
Some details: there are a few misplaced stars (new_sllist,
sllist_insert_after), you have inconsistent naming of new_sllist and
destroy_sllist (all others start with 'sllist') and new_sllist is missing void
parameter list.