The protocol though (in my opinion!) is a little tricky, where typically the tricks are: details.
In this first post of a series of "Trip-wires for the SIP fans", I'll talk about CANCEL.
The main concept is easy: a caller may decide to cancel a call before this is answered. To do this, it sends a CANCEL request to the called party.
What's important to know is that:
A CANCEL request relates to an INVITE request, and does not relate to the SIP dialog the request may have created (or will create).
For this reason the To header tag must be the same as the INVITE request, even if meanwhile there's been a provisional response to the INVITE creating a dialog (e.g. a 180 with a tag in the To header).
From RFC 3261, 9.1:
The following procedures are used to construct a CANCEL request. The
Request-URI, Call-ID, To, the numeric part of CSeq, and From header
fields in the CANCEL request MUST be identical to those in the
request being cancelled, including tags. A CANCEL constructed by a
client MUST have only a single Via header field value matching the
top Via value in the request being cancelled. Using the same values
for these header fields allows the CANCEL to be matched with the
request it cancels [...].
Although not so common I guess, consider that a CANCEL can be sent also for a re-INVITE (i.e. a request to update an ongoing session, e.g. to add video). In this case there will be a tag in the To header, as the INVITE is an in-dialog request and the CANCEL just refers to it.
And if you use sipp unfortunately no, you can't rely on the [branch] syntax to assign a branch to the Via in the CANCEL request, because sipp doesn't have perception of precedent open transactions.
If the branch in the CANCEL's Via header is different than the one in the INVITE top most Via, the UAS will not be able to match the two requests and canceling will (most likely) fail.